diff --git a/third_party/README b/third_party/README
new file mode 100644
index 0000000000000000000000000000000000000000..67c19db3484468823310cf027ebc674573a257fd
--- /dev/null
+++ b/third_party/README
@@ -0,0 +1,35 @@
+How to update libcoro
+=====================
+
+cvs up
+
+How to update libev
+===================
+
+cvs up
+
+How to update luajit
+====================
+
+- download the latest release source tarball
+- replace the contents of the luajit directory 
+with the contents of the tarball
+- merge the original Makefile and the Makefile
+from the new tarball.
+
+How to update libobjc2
+======================
+
+How initial import was done:
+
+svn co http://svn.gna.org/svn/gnustep/libs/libobjc2/trunk/ ./libobjc
+
+find . -name '.svn' | xargs rm -rf
+rm Makefile.clang
+rm GNUMakefile
+
+How to update it:
+
+- delete GNUMakefile
+- merge our Makefile with the Makefile in
+the source tarball
diff --git a/third_party/libobjc/ANNOUNCE b/third_party/libobjc/ANNOUNCE
new file mode 100644
index 0000000000000000000000000000000000000000..75950a35df6ccc3b83932a6661a0c06686c69ab7
--- /dev/null
+++ b/third_party/libobjc/ANNOUNCE
@@ -0,0 +1,41 @@
+GNUstep Objective-C Runtime 1.6.1
+===============================
+
+This is a point release to the seventh official release of the GNUstep
+Objective-C runtime (a.k.a.  libobjc2).  This runtime was designed to support
+the features of Objective-C 2 for use with GNUstep and other Objective-C
+programs.  Highlights of this release include:
+
+- Improved support for ARC autorelease pools.
+
+- Some small bug fixes in blocks support.
+
+- Improvements to the Objective-C++ unified exception model support.
+
+- Updated optimisation passes to work with LLVM 3.1
+
+You may obtain the code for this release from subversion at the following
+subversion branch:
+
+svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.6.1
+
+Alternatively, a tarball is available from:
+
+http://download.gna.org/gnustep/libobjc2-1.6.1.tar.bz2
+
+The runtime library is responsible for implementing the core features of the
+object model, as well as exposing introspection features to the user.  The
+GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number
+of GCC APIs for legacy compatibility.
+
+This library is based on the Étoilé Objective-C Runtime, an earlier research
+prototype, and includes support for non-fragile instance variables,
+type-dependent dispatch, and object planes.  It is fully backwards compatible
+with the FSF's GCC 4.2.1 Objective-C ABI and also implements a new ABI that is
+supported by Clang and Étoilé's LanguageKit and is required for some of the
+newer features.
+
+Although the runtime has been tested by several people, and is being used
+extensively by the Étoilé project, it is relatively new code and may still
+contain bugs.  If you come across any problems, please report them to the
+GNUstep Developer mailing list <gnustep-dev@gnu.org>.  
diff --git a/third_party/libobjc/ANNOUNCE.1.0 b/third_party/libobjc/ANNOUNCE.1.0
new file mode 100644
index 0000000000000000000000000000000000000000..730984d6edc50e7d3e1d6b0eb46d208981df6acf
--- /dev/null
+++ b/third_party/libobjc/ANNOUNCE.1.0
@@ -0,0 +1,33 @@
+GNUstep Objective-C Runtime 1.0
+===============================
+
+This is the first official release of the GNUstep Objective-C runtime (a.k.a.
+libobjc2).  This runtime was designed to support the features of Objective-C 2
+for use with GNUstep and other Objective-C programs.
+
+You may obtain the code for this release from subversion at the following
+subversion branch:
+
+svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.0
+
+Alternatively, a tarball is available from:
+
+http://download.gna.org/gnustep/libobjc2-1.0.tar.bz2
+
+The runtime library is responsible for implementing the core features of the
+object model, as well as exposing introspection features to the user.  The
+GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number
+of GCC APIs for legacy compatibility.
+
+This library is based on the Étoilé Objective-C Runtime, an earlier research
+prototype, and includes support for non-fragile instance variables,
+type-dependent dispatch, and object planes.  It is fully compatible with the
+FSF's GCC Objective-C ABI and also implements a new ABI that is supported by
+Clang and is required for some of the newer features.
+
+Although the runtime has been tested by several people, and is being used
+extensively by the Étoilé project, it is entirely new (MIT licensed) code and
+may still contain bugs.  If you come across any problems, please report them to
+the GNUstep Developer mailing list <gnustep-dev@gnu.org>.  A 1.1 release,
+fixing any bugs that are encountered in wider deployment, is planned to
+coincide with the next GNUstep release.
diff --git a/third_party/libobjc/ANNOUNCE.1.1 b/third_party/libobjc/ANNOUNCE.1.1
new file mode 100644
index 0000000000000000000000000000000000000000..68d0a2f216a2c40cfcb17d4b9b178e360e2a2819
--- /dev/null
+++ b/third_party/libobjc/ANNOUNCE.1.1
@@ -0,0 +1,33 @@
+GNUstep Objective-C Runtime 1.1
+===============================
+
+This is the second official release of the GNUstep Objective-C runtime (a.k.a.
+libobjc2).  This runtime was designed to support the features of Objective-C 2
+for use with GNUstep and other Objective-C programs.  This release contains
+minor bug fixes and provides compatibility with synthesised declared properties
+from GCC 4.6 and recent versions of clang.
+
+You may obtain the code for this release from subversion at the following
+subversion branch:
+
+svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.1
+
+Alternatively, a tarball is available from:
+
+http://download.gna.org/gnustep/libobjc2-1.1.tar.bz2
+
+The runtime library is responsible for implementing the core features of the
+object model, as well as exposing introspection features to the user.  The
+GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number
+of GCC APIs for legacy compatibility.
+
+This library is based on the Étoilé Objective-C Runtime, an earlier research
+prototype, and includes support for non-fragile instance variables,
+type-dependent dispatch, and object planes.  It is fully compatible with the
+FSF's GCC Objective-C ABI and also implements a new ABI that is supported by
+Clang and is required for some of the newer features.
+
+Although the runtime has been tested by several people, and is being used
+extensively by the Étoilé project, it is entirely new (MIT licensed) code and
+may still contain bugs.  If you come across any problems, please report them to
+the GNUstep Developer mailing list <gnustep-dev@gnu.org>.  
diff --git a/third_party/libobjc/ANNOUNCE.1.2 b/third_party/libobjc/ANNOUNCE.1.2
new file mode 100644
index 0000000000000000000000000000000000000000..aa54c993cca1fbc3e86e8a2e2bb97d7dd3b00acb
--- /dev/null
+++ b/third_party/libobjc/ANNOUNCE.1.2
@@ -0,0 +1,33 @@
+GNUstep Objective-C Runtime 1.2
+===============================
+
+This is the 1.2 release of the GNUstep Objective-C runtime (a.k.a.
+libobjc2).  This runtime was designed to support the features of Objective-C 2
+for use with GNUstep and other Objective-C programs.  This release contains
+several bug fixes, and is tested with the current GNUstep trunk, so will be
+compatible with the upcoming GNUstep release.
+
+You may obtain the code for this release from subversion at the following
+subversion branch:
+
+svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.2
+
+Alternatively, a tarball is available from:
+
+http://download.gna.org/gnustep/libobjc2-1.2.tar.bz2
+
+The runtime library is responsible for implementing the core features of the
+object model, as well as exposing introspection features to the user.  The
+GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number
+of GCC APIs for legacy compatibility.
+
+This library is based on the Étoilé Objective-C Runtime, an earlier research
+prototype, and includes support for non-fragile instance variables,
+type-dependent dispatch, and object planes.  It is fully compatible with the
+FSF's GCC Objective-C ABI and also implements a new ABI that is supported by
+Clang and is required for some of the newer features.
+
+Although the runtime has been tested by several people, and is being used
+extensively by the Étoilé project, it is entirely new (MIT licensed) code and
+may still contain bugs.  If you come across any problems, please report them to
+the GNUstep Developer mailing list <gnustep-dev@gnu.org>.  
diff --git a/third_party/libobjc/ANNOUNCE.1.3 b/third_party/libobjc/ANNOUNCE.1.3
new file mode 100644
index 0000000000000000000000000000000000000000..59d96f36b17e6b36df408058d245dfa9d01f7ae2
--- /dev/null
+++ b/third_party/libobjc/ANNOUNCE.1.3
@@ -0,0 +1,41 @@
+GNUstep Objective-C Runtime 1.3
+===============================
+
+This is the fourth official release of the GNUstep Objective-C runtime (a.k.a.
+libobjc2).  This runtime was designed to support the features of Objective-C 2
+for use with GNUstep and other Objective-C programs.
+
+This release contains several bug fixes and includes a unified exception
+model, providing the same features as Apple's Modern runtime for Objective-C++
+code, specifically the ability to throw Objective-C objects with @throw() or
+throw() and catch them with @catch() or catch().  The new unified exception
+model is supported by Clang 2.9 and is compatible with Apple's Objective-C++
+exception behaviour.  Another enhancement in this release is the addition of
+support for class aliases.  This provides a run-time equivalent of
+@compatibility_alias, allowing a class to show up in class lookup searching for
+its alias.
+
+You may obtain the code for this release from subversion at the following
+subversion branch:
+
+svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.3
+
+Alternatively, a tarball is available from:
+
+http://download.gna.org/gnustep/libobjc2-1.3.tar.bz2
+
+The runtime library is responsible for implementing the core features of the
+object model, as well as exposing introspection features to the user.  The
+GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number
+of GCC APIs for legacy compatibility.
+
+This library is based on the Étoilé Objective-C Runtime, an earlier research
+prototype, and includes support for non-fragile instance variables,
+type-dependent dispatch, and object planes.  It is fully compatible with the
+FSF's GCC Objective-C ABI and also implements a new ABI that is supported by
+Clang and Étoilé's LanguageKit and is required for some of the newer features.
+
+Although the runtime has been tested by several people, and is being used
+extensively by the Étoilé project, it is entirely new (MIT licensed) code and
+may still contain bugs.  If you come across any problems, please report them to
+the GNUstep Developer mailing list <gnustep-dev@gnu.org>.  
diff --git a/third_party/libobjc/ANNOUNCE.1.4 b/third_party/libobjc/ANNOUNCE.1.4
new file mode 100644
index 0000000000000000000000000000000000000000..0a723a1ee94b610ea95fb5ea141f8d31e47886fb
--- /dev/null
+++ b/third_party/libobjc/ANNOUNCE.1.4
@@ -0,0 +1,79 @@
+GNUstep Objective-C Runtime 1.4
+===============================
+
+This is the fifth official release of the GNUstep Objective-C runtime (a.k.a.
+libobjc2).  This runtime was designed to support the features of Objective-C 2
+for use with GNUstep and other Objective-C programs.  Highlights of this
+release include:
+
+- Support for the associated reference APIs introduced with OS X 10.6.  This
+  allows storing arbitrary objects associated with another object.
+
+- Concurrent, thread-safe, +initialize.  The runtime will now send +initialize
+  messages to different classes concurrently in multiple threads, but still
+  ensures that no class receives another message until it has returned from
+  +initialize.  This mirrors OS X behaviour.  Care must be taken that
+  +initialize methods do not deadlock - if two classes are simultaneously
+  initialised from two different threads, and there +initialize methods call
+  methods in the other class, then deadlock will result.
+  
+- Exceptions can now safely propagate out of +initialize methods.
+
+- Better hiding of local symbols.  Now the internal runtime functions are not
+  visible from outside of the runtime.  This may break code that attempts to
+  use private APIs, but means that it is now impossible to accidentally use
+  private APIs.
+
+- Dispatch table updates have been improved.  Category loading now longer
+  triggers dtable creation and partial dtable updates are faster.  
+
+- Improvements to the low memory profile.  Uses 5-10% less (total) memory
+  running Gorm, and now passes the entire GNUstep and EtoileFoundation test
+  suites.  Build with [g]make low_memory=yes to enable this mode.  Note that
+  the low memory profile trades some CPU time for memory usage, so don't use it
+  for CPU-bound tasks.
+
+- The class lookup cache optimisation (LLVM) now caches lookups irrespective of
+  the ABI.  It will insert direct references to the class structures if
+  possible (i.e. if the symbol is visible).  If not, then it will cache the
+  result of objc_class_lookup().  The cache is shared across the module (the
+  library, if run as a link-time optimisation), so the lookup only needs to be
+  run once.  This eliminates the need for explicit class lookup caching in the
+  source code (when using LLVM-based compilers, such as Clang, LanguageKit, or
+  DragonEgg).
+
+- Added some missing runtime API functions, such as those for setting and
+  getting instance variables.  These are required by some language bridges,
+  although using them safely is not actually possible with the non-fragile ABI
+  (also true on OS X), since instance variables are no longer uniquely
+  identified by name. 
+  
+- Added support for accessing property type encodings.  These are extended type
+  encodings, allowing code introspecting the properties to learn if they are
+  read-only, their assignment policy, the methods used to implement them, and
+  so on.
+
+You may obtain the code for this release from subversion at the following
+subversion branch:
+
+svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.4
+
+Alternatively, a tarball is available from:
+
+http://download.gna.org/gnustep/libobjc2-1.4.tar.bz2
+
+The runtime library is responsible for implementing the core features of the
+object model, as well as exposing introspection features to the user.  The
+GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number
+of GCC APIs for legacy compatibility.
+
+This library is based on the Étoilé Objective-C Runtime, an earlier research
+prototype, and includes support for non-fragile instance variables,
+type-dependent dispatch, and object planes.  It is fully compatible with the
+FSF's GCC Objective-C ABI and also implements a new ABI that is supported by
+Clang and Étoilé's LanguageKit and is required for some of the newer features.
+
+Although the runtime has been tested by several people, and is being used
+extensively by the Étoilé project, it is entirely new (MIT licensed) code and
+may still contain bugs.  If you come across any problems, please report them to
+the GNUstep Developer mailing list <gnustep-dev@gnu.org>.  
diff --git a/third_party/libobjc/ANNOUNCE.1.5 b/third_party/libobjc/ANNOUNCE.1.5
new file mode 100644
index 0000000000000000000000000000000000000000..bdf8d81d9350249c2d4b6ba3cc22a965b7dc8b71
--- /dev/null
+++ b/third_party/libobjc/ANNOUNCE.1.5
@@ -0,0 +1,55 @@
+GNUstep Objective-C Runtime 1.5
+===============================
+
+This is the sixth official release of the GNUstep Objective-C runtime (a.k.a.
+libobjc2).  This runtime was designed to support the features of Objective-C 2
+for use with GNUstep and other Objective-C programs.  Highlights of this
+release include:
+
+- Support for Apple-compatible garbage collection APIs, along with extensions
+  to support CoreFoundation-style explicit reference counting in a garbage
+  collected environment.  This uses the Boehm garbage collector and is enabled
+  by specifying boehm_gc=yes when building.  This requires version 7.1 or later
+  of libgc.  Code compiled with -fobjc-gc can be mixed with code that
+  implements normal reference counting and with code compiled with
+  -fobjc-gc-only.  The runtime supports both GC and non-GC code when compiled
+  with GC support and will automatically select the correct behavior depending
+  on the loaded code.
+
+- The runtime will now use Boehm GC for several internal data structures, if it
+  is built with GC enabled.  This avoids the need for defensive programming
+  with respect to thread safety in several places.
+
+- This is the first release to provide a superset of the functionality provided
+  by the Mac Objective-C runtime, as shipped with OS X 10.6.
+
+- Full support for Automatic Reference Counting (ARC), compatible with OS X
+  10.7 and iOS 5, including support for __weak references.
+
+- The LLVM optimisation passes have been improved and better tested.  Code
+  compiled with them now passes the EtoileFoundation test suite.
+
+You may obtain the code for this release from subversion at the following
+subversion branch:
+
+svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.5
+
+Alternatively, a tarball is available from:
+
+http://download.gna.org/gnustep/libobjc2-1.5.tar.bz2
+
+The runtime library is responsible for implementing the core features of the
+object model, as well as exposing introspection features to the user.  The
+GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number
+of GCC APIs for legacy compatibility.
+
+This library is based on the Étoilé Objective-C Runtime, an earlier research
+prototype, and includes support for non-fragile instance variables,
+type-dependent dispatch, and object planes.  It is fully compatible with the
+FSF's GCC Objective-C ABI and also implements a new ABI that is supported by
+Clang and Étoilé's LanguageKit and is required for some of the newer features.
+
+Although the runtime has been tested by several people, and is being used
+extensively by the Étoilé project, it is entirely new (MIT licensed) code and
+may still contain bugs.  If you come across any problems, please report them to
+the GNUstep Developer mailing list <gnustep-dev@gnu.org>.  
diff --git a/third_party/libobjc/ANNOUNCE.1.6 b/third_party/libobjc/ANNOUNCE.1.6
new file mode 100644
index 0000000000000000000000000000000000000000..618ab6ce8b47ecf8b28926d6203b3372d5684240
--- /dev/null
+++ b/third_party/libobjc/ANNOUNCE.1.6
@@ -0,0 +1,64 @@
+GNUstep Objective-C Runtime 1.6
+===============================
+
+This is the seventh official release of the GNUstep Objective-C runtime (a.k.a.
+libobjc2).  This runtime was designed to support the features of Objective-C 2
+for use with GNUstep and other Objective-C programs.  Highlights of this
+release include:
+
+- Compatibility with the new runtime APIs introduced with Mac OS X 10.7 / iOS 5.
+
+- Support for small objects (ones hidden inside a pointer).  On 32-bit systems,
+  the runtime permits one small object class, on 64-bit systems it permits 4.
+  This is used by GNUstep for small NSNumber and NSString instances, and these
+  are used by LanguageKit for message sending to small integers. 
+
+- Support for prototype-style object orientation.  You can now add methods, as
+  well as associated references, to individual objects, and clone them.  The
+  runtime now supports everything required for the JavaScript object model,
+  including the ability to use blocks as methods on x86, x86-64 and ARM.
+
+- Support for Apple-compatible objc_msgSend() functions for x86, x86-64, and
+  ARM.  Using these approximately halves the cost of message sending operations
+  and results in a 10% smaller total binary size.  
+
+- A fully maintained POSIX Makefile to make bootstrapping builds and packaging
+  easier.  This will be used automatically if GNUstep Make is not installed.
+
+- Improvements to the included LLVM optimisation passes.  Testing on a 2.8GHz
+  Xeon, a loop of 200,000,000 class messages took 0.8 seconds with all
+  optimisations enabled (including speculative inlining).  With -Os, the test
+  took 2 seconds.  With explicit IMP caching in the source code, the test took
+  1.2 seconds.  For reference, the same test using the GCC Objective-C runtime
+  took 11 seconds (when compiled with either Clang/LLVM or GCC).
+
+Various features of this release required some per-platform assembly code.  For
+the 1.6.0 release, ARM, x86 and x86-64 (with the SysV ABI, not with the Win64
+ABI) are supported.  Future releases in the 1.6.x series will extend this to
+other architectures.  
+
+You may obtain the code for this release from subversion at the following
+subversion branch:
+
+svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.6
+
+Alternatively, a tarball is available from:
+
+http://download.gna.org/gnustep/libobjc2-1.6.tar.bz2
+
+The runtime library is responsible for implementing the core features of the
+object model, as well as exposing introspection features to the user.  The
+GNUstep runtime implements Apple's Objective-C Runtime APIs, and a small number
+of GCC APIs for legacy compatibility.
+
+This library is based on the Étoilé Objective-C Runtime, an earlier research
+prototype, and includes support for non-fragile instance variables,
+type-dependent dispatch, and object planes.  It is fully backwards compatible
+with the FSF's GCC 4.2.1 Objective-C ABI and also implements a new ABI that is
+supported by Clang and Étoilé's LanguageKit and is required for some of the
+newer features.
+
+Although the runtime has been tested by several people, and is being used
+extensively by the Étoilé project, it is relatively new code and may still
+contain bugs.  If you come across any problems, please report them to the
+GNUstep Developer mailing list <gnustep-dev@gnu.org>.  
diff --git a/third_party/libobjc/API b/third_party/libobjc/API
new file mode 100644
index 0000000000000000000000000000000000000000..a65c0be395da8369166212fcc0c3e6e670c19813
--- /dev/null
+++ b/third_party/libobjc/API
@@ -0,0 +1,134 @@
+GNUstep Runtime APIs
+====================
+
+The GNUstep Objective-C runtime aims to implement all of the APIs defined in
+Apple's Objective-C Runtime Reference.  That document should be taken as the
+authoritative reference to the majority of the APIs exposed by this runtime.
+Any discrepancies between the implementations in this runtime and the
+documentation should be regarded as a bug in the runtime.
+
+In addition to these APIs, the runtime also exposes some non-portable APIs.
+These are all marked as OBJC_NONPORTABLE in the headers.  Many of these APIs
+are also implemented in GNUstep's ObjectiveC2 framework, which uses the GCC
+Objective-C runtime for the underlying implementation and provides a portable
+set of APIs on top of the GCC runtime structures and functions.
+
+Runtime Capabilities
+--------------------
+
+The objc/capabilities.h header defines runtime capabilities.  A copy of this
+header is also present in the ObjectiveC2 framework, so you can conditionally
+include either version.
+
+You can perform two sorts of checks using this header.  Constants declared in
+the header describe capabilities that the runtime may or may not implement.  If
+a capability is missing from this header, then it means that you are using an
+old version of the runtime, which lacks any knowledge of the header.  You can
+use this to refuse to compile with old runtime versions.
+
+You can also use the objc_test_capability() function to test whether a
+particular capability is present at run time.  Several of the capabilities are
+optional in this runtime, and may not be compiled in to a given install.  If
+you require a particular capability, you can use the OBJC_REQUIRE_CAPABILITY()
+macro to insert a load function that will abort if the capability is not present.
+
+This shows how to refuse to compile or run with versions of the runtime that do
+not support type-dependent dispatch:
+
+	#ifndef OBJC_CAP_TYPE_DEPENDENT_DISPATCH
+	#	error Type-dependent dispatch support required!
+	#else
+	OBJC_REQUIRE_CAPABILITY(OBJC_CAP_TYPE_DEPENDENT_DISPATCH);
+	#endif
+
+Typed Selectors
+---------------
+
+Like the GCC runtime, this runtime uses typed selectors.  In recent versions,
+message lookup is also dependent on the type of the selector by default.  This
+can be disabled by not defining the TYPE_DEPENDENT_DISPATCH macro when
+building.  When using GNU make, you can get name-dependent dispatch by doing:
+
+	$ gmake tdd=no
+
+This is strongly discouraged.  It will give compatibility with the semantics of
+the NeXT, Apple, and GCC runtimes, however these semantics include random stack
+corruption from valid code.
+
+There are three functions for dealing with typed selectors.  The first two are
+direct equivalents of other functions.
+
+	SEL sel_registerTypedName_np(const char *selName, const char *types);
+
+sel_registerName() will register an untyped selector.  This variant registers a
+typed selector, using the specified name and type encoding.
+
+	const char *sel_getType_np(SEL aSel);
+
+This function simply returns the type encoding of the given selector, or NULL for a typed selector.
+
+	unsigned sel_copyTypes_np(const char *selName,
+	                          const char **types,
+	                          unsigned count);
+
+This function copies *all* of the type encodings for a given selector name.
+Generally, there are not many of these.  In a well-written program, there will
+be exactly one type encoding for a given selector.  In a typical program, there
+will be 1-3.  It is not worth allocating a buffer on the heap for most cases,
+so this function is designed to take a stack buffer.
+
+Unlike other functions in the runtime, this always returns the total number of
+type encodings, not the number that were found.  This means that you can call
+it once with a smallish on-stack buffer and then call it again with a
+malloc()'d buffer if there are a lot of encodings for a specific selector, as
+follows.
+
+	char *t[16];
+	char *types = t;
+	unsigned total = sel_copyTypes_np("alloc", types, total);
+	if (total > 16)
+	{
+		types = calloc(sizeof(char*), total);
+		sel_copyTypes_np("alloc", types, total);
+	}
+	// Do stuff with the types.
+	if (total > 16)
+	{
+		free(types);
+	}
+
+
+**Note**: This runtime does not provide any equivalent of the GCC runtime's
+sel_get_typed_uid() or sel_get_any_typed_uid().  This is intentional.  It is
+impossible to use these functions correctly and they should never have been
+made part of the public API.
+
+Message Sending
+---------------
+
+For ABI compatibility with the GCC runtime, this runtime implements the
+objc_msg_lookup() and objc_msg_lookup_super() functions used to implement
+message sending.
+
+The new ABI uses the objc_msg_lookup_sender() function in place of
+objc_msg_lookup().  This allows fast proxies and caching of the lookup result
+at the callsite.  You can find more a detailed explanation of how this works in
+the README file.
+
+This runtime also provides this semi-private function, which can be of use in
+implementing parts of the Foundation framework and similar low-level libraries:
+
+	struct objc_slot* objc_get_slot(Class cls, SEL selector);
+
+This looks up the slot for a given selector, without invoking any forwarding
+mechanisms.  This is most useful for quickly finding the type encoding of a
+method (e.g. for implementing forwarding).  The lookup is as fast as a normal
+message lookup, and the types field of the returned slot provides the type
+encoding.  This is significantly faster than using class_getInstanceMethod(),
+which needs to perform a linear search along a list (O(1) vs O(n)).
+
+Hooks
+-----
+
+All of the callback hooks provided by this runtime are described in
+objc/hooks.h.
diff --git a/third_party/libobjc/COPYING b/third_party/libobjc/COPYING
new file mode 100644
index 0000000000000000000000000000000000000000..8647a56b739dfc73c8501a1a06ecbd7e75f737e4
--- /dev/null
+++ b/third_party/libobjc/COPYING
@@ -0,0 +1,20 @@
+Copyright (c) 2009 David Chisnall
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/third_party/libobjc/NSBlocks.m b/third_party/libobjc/NSBlocks.m
new file mode 100644
index 0000000000000000000000000000000000000000..32870da35aa4fdf937c52da4f861f512504c60ec
--- /dev/null
+++ b/third_party/libobjc/NSBlocks.m
@@ -0,0 +1,52 @@
+#import "objc/runtime.h"
+#import "class.h"
+#import "lock.h"
+#import "objc/blocks_runtime.h"
+#import "dtable.h"
+#include <assert.h>
+
+struct objc_class _NSConcreteGlobalBlock;
+struct objc_class _NSConcreteStackBlock;
+struct objc_class _NSConcreteMallocBlock;
+
+static struct objc_class _NSConcreteGlobalBlockMeta;
+static struct objc_class _NSConcreteStackBlockMeta;
+static struct objc_class _NSConcreteMallocBlockMeta;
+
+static struct objc_class _NSBlock;
+static struct objc_class _NSBlockMeta;
+
+static void createNSBlockSubclass(Class superclass, Class newClass, 
+		Class metaClass, char *name)
+{
+	// Initialize the metaclass
+	//metaClass->class_pointer = superclass->class_pointer;
+	//metaClass->super_class = superclass->class_pointer;
+	metaClass->info = objc_class_flag_meta;
+	metaClass->dtable = uninstalled_dtable;
+
+	// Set up the new class
+	newClass->isa = metaClass;
+	newClass->super_class = (Class)superclass->name;
+	newClass->name = name;
+	newClass->info = objc_class_flag_class;
+	newClass->dtable = uninstalled_dtable;
+
+	LOCK_RUNTIME_FOR_SCOPE();
+	class_table_insert(newClass);
+
+}
+
+#define NEW_CLASS(super, sub) \
+	createNSBlockSubclass(super, &sub, &sub ## Meta, #sub)
+
+BOOL objc_create_block_classes_as_subclasses_of(Class super)
+{
+	if (_NSBlock.super_class != NULL) { return NO; }
+
+	NEW_CLASS(super, _NSBlock);
+	NEW_CLASS(&_NSBlock, _NSConcreteStackBlock);
+	NEW_CLASS(&_NSBlock, _NSConcreteGlobalBlock);
+	NEW_CLASS(&_NSBlock, _NSConcreteMallocBlock);
+	return YES;
+}
diff --git a/third_party/libobjc/Protocol2.m b/third_party/libobjc/Protocol2.m
new file mode 100644
index 0000000000000000000000000000000000000000..7897b4387978339d9f9857de3cfbebc92d0d6464
--- /dev/null
+++ b/third_party/libobjc/Protocol2.m
@@ -0,0 +1,34 @@
+#include "objc/runtime.h"
+#include "protocol.h"
+#include "class.h"
+#include <stdio.h>
+#include <string.h>
+
+@implementation Protocol
+// FIXME: This needs removing, but it's included for now because GNUstep's
+// implementation of +[NSObject conformsToProtocol:] calls it.
+- (BOOL)conformsTo: (Protocol*)p
+{
+	return protocol_conformsToProtocol(self, p);
+}
+- (id)retain
+{
+	return self;
+}
+- (void)release {}
++ (Class)class { return self; }
+- (id)self { return self; }
+@end
+@implementation Protocol2 @end
+
+/**
+ * This class exists for the sole reason that the legacy GNU ABI did not
+ * provide a way of registering protocols with the runtime.  With the new ABI,
+ * every protocol in a compilation unit that is not referenced should be added
+ * in a category on this class.  This ensures that the runtime sees every
+ * protocol at least once and can perform uniquing.
+ */
+@interface __ObjC_Protocol_Holder_Ugly_Hack { id isa; } @end
+@implementation __ObjC_Protocol_Holder_Ugly_Hack @end
+
+@implementation Object @end
diff --git a/third_party/libobjc/README b/third_party/libobjc/README
new file mode 100644
index 0000000000000000000000000000000000000000..ec106c09a92d4ece035258dd24aa4954e672adc4
--- /dev/null
+++ b/third_party/libobjc/README
@@ -0,0 +1,464 @@
+GNUstep Objective-C Runtime
+===========================
+
+The GNUstep Objective-C runtime is designed as a drop-in replacement for the
+GCC runtime.  It supports both a legacy and a modern ABI, allowing code
+compiled with old versions of GCC to be supported without requiring
+recompilation.  The modern ABI adds the following features:
+
+- Non-fragile instance variables.
+- Protocol uniquing.
+- Object planes support.
+- Declared property introspection.
+
+Both ABIs support the following feature above and beyond the GCC runtime:
+
+- The modern Objective-C runtime APIs, introduced with OS X 10.5.
+- Blocks (closures).
+- Low memory profile for platforms where memory usage is more important than
+  speed.
+- Synthesised property accessors.
+- Efficient support for @synchronized()
+- Type-dependent dispatch, eliminating stack corruption from mismatched
+  selectors.
+- Support for the associated reference APIs introduced with Mac OS X 10.6.
+- Support for the automatic reference counting APIs introduced with Mac OS X
+  10.7
+
+History
+-------
+
+Early work on the GNUstep runtime combined code from the GCC Objective-C
+runtime, the Étoilé Objective-C runtime, Remy Demarest's blocks runtime for OS
+X 10.5, and the Étoilé Objective-C 2 API compatibility framework.  All of these
+aside from the GCC runtime were MIT licensed, although the GPL'd code present
+in the GCC runtime meant that the combined work had to remain under the GPL.
+
+Since then, all of the GCC code has been removed, leaving the remaining files
+all MIT licensed, and allowing the entire work to be MIT licensed.  
+
+The exception handling code uses a header file implementing the generic parts
+of the Itanium EH ABI.  This file comes from PathScale's libcxxrt.  PathScale
+kindly allowed it to be MIT licensed for inclusion here.
+
+Non-Fragile Instance Variables
+------------------------------
+
+When a class is compiled to support non-fragile instance variables, the
+instance_size field in the class is set to 0 - the size of the instance
+variables declared on that class (excluding those inherited.  For example, an
+NSObject subclass declaring an int ivar would have its instance_size set to 0 -
+sizeof(int)).  The offsets of each instance variable in the class's ivar_list
+field are then set to the offset from the start of the superclass's ivars.
+
+When the class is loaded, the runtime library uses the size of the superclass
+to calculate the correct size for this new class and the correct offsets.  Each
+instance variable should have two other variables exported as global symbols.
+Consider the following class:
+
+@interface NewClass : SuperClass {
+	int anIvar;
+}
+@end
+
+This would have its instance_size initialized to 0-sizeof(int), and anIvar's
+offset initialized to 0.  It should also export the following two symbols:
+
+int __objc_ivar_offset_value_NewClass.anIvar;
+int *__objc_ivar_offset_NewClass.anIvar;
+
+The latter should point to the former or to the ivar_offset field in the ivar
+metadata.  The former should be pointed to by the only element in the
+ivar_offsets array in the class structure.  
+
+In other compilation units referring to this ivar, the latter symbol should be
+exported as a weak symbol pointing to an internal symbol containing the
+compiler's guess at the ivar offset.  The ivar will then work as a fragile ivar
+when NewClass is compiled with the old ABI.  If NewClass is compiled with the
+new ABI, then the linker will replace the weak symbol with the version in the
+class's compilation unit and references which use this offset will function
+correctly.
+
+If the compiler can guarantee that NewClass is compiled with the new ABI, for
+example if it is declared in the same compilation unit, by finding the symbol
+during a link-time optimization phase, or as a result of a command-line
+argument, then it may use the __objc_ivar_offset_value_NewClass.anIvar symbol
+as the ivar offset.  This eliminates the need for one load for every ivar
+access.  
+
+Protocols
+---------
+
+The runtime now provides a __ObjC_Protocol_Holder_Ugly_Hack class.  All
+protocols that are referenced but not defined should be registered as
+categories on this class.  This ensures that every protocol is registered with
+the runtime.  
+
+In the near future, the runtime will ensure that protocols can be looked up by
+name at run time and that empty protocol definitions have their fields updated
+to match the defined version.
+
+Protocols have been extended to provide space for introspection on properties
+and optional methods.  These fields only exist on protocols compiled with a
+compiler that supports Objective-C 2.  To differentiate the two, the isa
+pointer for new protocols will be set to the Protocol2 class.
+
+Blocks
+------
+
+The GNUstep runtime provides the run time support required for Apple's blocks
+(closures) extension to C.  This follows the same ABI as OS X 10.6.
+
+Fast Proxies and Cacheable Lookups
+----------------------------------
+
+The new runtime provides two mechanisms for faster lookup.  The older
+Vobjc_msg_lookup() function, which returns an IMP, is still supported, however
+it is no longer recommended.  The new lookup functions is:
+
+Slot_t objc_msg_lookup_sender(id *receiver, SEL selector, id sender)
+
+The receiver is passed by pointer, and so may be modified during the lookup
+process.  The runtime itself will never modify the receiver.  The following
+hook is provided to allow fast proxy support:
+
+id (*objc_proxy_lookup)(id receiver, SEL op);
+
+This function takes an object and selector as arguments and returns a new
+objects.  The lookup will then be re-run and the final message should be sent to
+the new object.
+
+The returned Slot_t from the new lookup function is a pointer to a structure
+which contains both an IMP and a version (among other things).  The version is
+incremented every time the method is overridden, allowing this to be cached by
+the caller.  User code wishing to perform IMP caching may use the old mechanism
+if it can guarantee that the IMP will not change between calls, or the newer
+mechanism.  Note that a modern compiler should insert caching automatically,
+ideally with the aid of run-time profiling results.  To support this, a new hook
+has been added:
+
+Slot_t objc_msg_forward3(id receiver, SEL op);
+
+This is identical to objc_msg_forward2(), but returns a pointer to a slot,
+instead of an IMP.  The slot should have its version set to 0, to prevent
+caching.
+
+Object Planes
+-------------
+
+Object planes provide interception points for messages between groups of
+related objects.  They can be thought of as similar to processes, with mediated
+inter-plane communication.  A typical use-case for an object plane is to
+automatically queue messages sent to a thread, or to record every message sent
+to model objects.  Planes can dramatically reduce the number of proxy objects
+required for this kind of activity.
+
+The GNUstep runtime adds a flag to class objects indicating that their
+instances are present in the global plane.  All constant strings, protocols,
+and classes are in the global plane, and may therefore be sent and may receive
+messages bypassing the normal plane interception mechanism.  
+
+The runtime library does not provide direct support for planes, it merely
+provides the core components required to implement support for planes in
+another framework.  Two objects are regarded as being in the same plane when
+they words immediately before their isa pointers are the same.  In this case,
+the runtime's usual dispatch mechanisms will be used.  In all other cases, the
+runtime will delegate message lookup to another library via the following hook:
+
+Slot_t (*objc_plane_lookup)(id *receiver, SEL op, id sender);
+
+From the perspective of the runtime, the plane identifier is opaque.  In
+GNUstep, it is a pointer to an NSZone structure.
+
+Threading
+---------
+
+The threading APIs from GCC libobjc are not present in this runtime.  They were
+buggy, badly supported, inadequately tested, and irrelevant now that there are
+well tested thread abstraction layers, such as the POSIX thread APIs and the
+C1x thread functions.  The library always runs in thread-safe mode.  The same
+functions for locking the runtime mutex are still supported, but their use any
+mutex not exported by the runtime library is explicitly not supported.  The
+(private) lock.h header is used to abstract the details of different threading
+systems sufficiently for the runtime.  This provides mechanisms for locking,
+unlocking, creating, and destroying mutex objects.  
+
+Type-Dependent Dispatch
+-----------------------
+
+Traditionally, Objective-C method lookup is done entirely on the name of the
+method.  This is problematic when the sender and receiver of the method
+disagree on the types of a method.  
+
+For example, consider a trivial case where you have two methods with the same
+name, one taking an integer, the other taking a floating point value.  Both
+will pass their argument in a register on most platforms, but not the same
+register.  If the sender thinks it is calling one, but is really calling the
+other, then the receiver will look in the wrong register and use a nonsense
+value.  The compiler will often not warn about this.
+
+This is a relatively benign example, but if the mismatch is between methods
+taking or returning a structure and those only using scalar arguments and
+return then the call frame layout will be so different that the result will be
+stack corruption, possibly leading to security holes.
+
+If you compile the GNUstep runtime with type-dependent dispatch enabled, then
+sending a message with a typed selector will only ever invoke a method with the
+same types.  Sending a message with an untyped selector will invoke any method
+with a matching name, although the slot returned from the lookup function will
+contain the types, allowing the caller to check them and construct a valid call
+frame, if required.
+
+If a lookup with a typed selector matches a method with the wrong types, the
+runtime will call a handler.  This handler, by default, prints a helpful
+message and exits.  LanguageKit provides an alternative version which
+dynamically generates a new method performing the required boxing and calling
+the original.
+
+Exception ABI Changes
+---------------------
+
+The non-fragile ABI makes a small change to the exception structure.  The old
+GCC ABI was very poorly designed.  It attempted to do things in a clever way,
+avoiding the need to call functions on entering and exiting catch blocks, but
+in doing so completely broke support for throwing foreign (e.g. C++) exceptions
+through Objective-C stack frames containing an @finally or @catch(id) block.
+It also could not differentiate between @catch(id) (catch any object type) and
+@catch(...) (catch any exception and discard it).
+
+The new ABI makes a small number of changes.  Most importantly, @catch(id) is
+now indicated by using the string "@id" as the type ID, in the same way that
+"Foo" is used for @catch(Foo*).  Catchalls remain identified by a NULL pointer
+in this field, as with the GCC ABI.  The runtime will still deliver the
+exception object to catchalls, for interoperability with old code and with the
+old ABI, but this comes with all of the same problems that the old ABI had
+(i.e. code using this ABI will break in exciting and spectacular ways when
+mixed with C++).
+
+The runtime provides a hook, _objc_class_for_boxing_foreign_exception(), which
+takes an exception class (64-bit integer value) as an argument, and returns a
+class for boxing exceptions using this ABI.  The returned class must implement
+a +exceptionWithForeignException: method, taking a pointer to the ABI-defined
+generic exception structure as the argument.  It should also implement a
+-rethrow method, used for rethrowing the exception.  If this is omitted, then
+the boxed version of the exception, rather than the original, will propagate
+out from @finally blocks.
+
+If a catch block exists that handles this class, then it will box foreign
+exceptions and allow them to propagate through any @finally directives.  Boxed
+exceptions will only match explicit catch statements.  To fully understand the
+semantics, we'll take a look at some examples.  These all use GNUstep's
+`CXXException` class, which boxes C++ exceptions, and this simple C++ function:
+
+	extern "C" void throwcxx()
+	{
+		throw 1;
+	}
+
+This exception will be caught, boxed, and then silently discarded by a catchall:
+
+	@try
+	{
+		throwcxx();
+	}
+	@catch(...)
+	{
+		// This will be reached, then the exception propagation stops.
+	}
+
+If an id catch block is encountered, it will be ignored, but @finally blocks
+will still be called:
+
+	@try
+	{
+		throwcxx();
+	}
+	@catch(id anyObject)
+	{
+		// Code here is not reached.
+	}
+	@finally
+	{
+		// This will be reached, then the exception propagation continues.
+	}
+
+The `CXXException` class is a subclass of `NSObject`, but catch statements for
+the superclass will not be hit:
+
+	@try
+	{
+		throwcxx();
+	}
+	@catch(NSObject *anyObject)
+	{
+		// Code here is not reached.
+	}
+	@catch(CXXException *boxedForeign)
+	{
+		// Code here is reached.
+	}
+
+As of version 1.3, the runtime also provides a unified exception model for
+Objective-C++.  This allows C++ `catch` statements and Objective-C `@catch`
+statements to catch Objective-C objects thrown with `@throw` or `throw`.
+
+This required some small changes to the ABI.  Both `@try` and `try` must use
+the same personality function in Objective-C++ code, because otherwise things
+like nested blocks are not possible.  The unwind library must be able to map
+from any instruction pointer value to a single personality function, and
+without a unified personality function, it would not be able to in code like
+this:
+
+	@try
+	{
+		try
+		{
+			// What personality function should be used when unwinding from
+			// here?
+			objc_exception_throw(@"foo");
+		}
+		catch (int i) {}
+	}
+	catch (id foo) {}
+
+If there is a single personality function, there must be a single format for
+language-specific data.  The current C++ format is more expressive than the
+Objective-C format, so we used it directly, with one extension.  C++ landing
+pads are identified by a `std::type_info` subclass in the type info tables for
+exception unwinding.  We provide two subclasses of this: 
+
+	gnustep::libobjc::__objc_id_type_info;
+	gnustep::libobjc::__objc_class_type_info;
+
+The first is used for identifying `id`-typed throws and catches.  The second is
+for identifying Objective-C classes.  All `id` throws use the singleton
+instance of the first class, exported as `__objc_id_type_info` (with C
+linkage).  Type info for classes should generate an instance of the second
+class, with the name `__objc_eh_typeinfo_Foo` where `Foo` is the name of the
+class (e.g. `NSObject` should generate `__objc_eh_typeinfo_NSObject`).  The
+name field should be set to the name of the class, via a global variable named
+`__objc_eh_typename_Foo`.  Both should have link-once ODR linkage, so that the
+linker will ensure that they are unique and pointer comparison can be used to
+test for equality (required by the C++ personality function).
+
+In Objective-C++ code, the personality function is:
+
+	__gnustep_objcxx_personality_v0()
+
+This is a very thin wrapper around the C++ personality function.  If it is
+called with an exception coming from Objective-C code, then it wraps it in a
+__cxa_exception structure (defined by the C++ ABI spec).  For any other
+exception type (including C++ exceptions), it passes it directly to the C++
+personality function.
+
+The Objective-C personality function was also modified slightly so that any
+incoming C++ exception that was has type info indicating that it's an
+Objective-C type is treated as an Objective-C object, for the purpose of
+exception delivery.
+
+Low Memory Profile
+------------------
+
+The dispatch tables for each class, in spite of using a more space-efficient
+sparse array implementation than GCC libobjc, can still use quite a lot of
+memory.  The NeXT runtime avoided this problem by not providing dispatch tables
+at all.  Instead, it did a linear search of the method lists, caching a few
+results.  Although this is O(n), it performed reasonably well.  Most message
+sends are to a small number of methods.  For example, an NSMutableDictionary is
+most often sent -objectForKey: and -setObject:forKey:.  If these two methods
+are in the cache, then the O(n) algorithm is almost never used.
+
+The GNUstep runtime's low memory profile stores the slots in a sorted array.
+This means that the worst case performance is O(log(n)) in terms of the number
+of methods, as the uncached lookup proceeds using a binary search.
+
+If you compile the GNUstep runtime with the low memory profile, it uses a
+similar strategy.  The caches use the same slot-caching mechanism described
+above and can be combined with caching at the call site.  The runtime will not
+create dispatch tables, which can save a few MB of RAM in projects with a lot
+of classes, but can make message sending a lot slower in the worst case.
+
+To enable the low memory profile, add low_memory=yes to your make command line.
+
+Objective-C 2 Features
+----------------------
+
+The runtime now provides implementations of the functions required for the
+@synchronized directive, for property accessors, and for fast enumeration.  The
+public runtime function interfaces now match those of OS X.
+
+Garbage Collection
+------------------
+
+As of version 1.5, the runtime support Apple-compatible garbage collection
+semantics.  The `objc/objc-auto.h` header describes the interfaces to garbage
+collection.  This contains some extensions to Apple's API, required to
+implement parts of Cocoa that rely on private interfaces between Cocoa, Apple
+libobjc, and Autozone.
+
+Garbage collection is implemented using the Boehm-Demers-Weiser garbage
+collector.  If built with boehm_gc=no, this support will not be compiled into
+the runtime.  When built with GC support, the runtime will use garbage
+collection for its internal tables, irrespective of whether linked Objective-C
+code is using it.
+
+Zeroing weak references are implemented by storing the bit-flipped version of
+the value (making it invisible to the collector) at the designated address.
+The read barrier reads the value while holding the collector lock.  This
+ensures that reads of weak variables never point to finalised objects.
+
+The runtime uses the objc_assign_global() write barrier to add static roots.
+Currently, GNUstep crashes if the collector relies on every write of a pointer
+to a static location being through this write barrier, so this requirement is
+relaxed.  It will be enabled at some point in the future.
+
+Several environment variables can be used for debugging programs
+
+- LIBOBJC_DUMP_GC_STATUS_ON_EXIT.  I this is set, then the program will dump
+  information about the garbage collector when it exits.
+- LIBOBJC_DUMP_GC_STATUS_ON_SIGNAL.  This should be set to a signal number.
+  The program will dump GC statistics when it receives the corresponding signal
+  (SIGUSR2 if this environment variable is set to something that is not a
+  number).
+- LIBOBJC_LOG_ALLOCATIONS.  This may be set to the name of a file.  The runtime
+  will dump a stack trace on every allocation and finalisation to the named
+  file.  This can be used to implement tools like Apple's malloc_history().
+  Note: Enabling this causes a significant speed decrease.
+- LIBOBJC_CANARIES.  If this environment variable is set, then every allocation
+  of garbage-collected memory will have a canary value appended to it.  On
+  finalisation, the runtime will check that this value has not been modified,
+  and abort if it has.  This can help to catch heap buffer overflows.  It is
+  most useful when debugging.
+
+Automatic Reference Counting
+----------------------------
+
+As of version 1.5, the runtime provides support for automatic reference
+counting (ARC).  This uses the same runtime interface as documented by the ABI
+supplement here:
+
+http://clang.llvm.org/docs/AutomaticReferenceCounting.html#runtime
+
+The runtime implements the following optimisations:
+
+- Classes that have ARC-compliant retain, release, and autorelease methods will
+  never see them called from ARC code.  Instead, equivalent code will be run
+  directly.
+- If an object is autoreleased, returned, and retained, it is just stored in
+  thread-local storage temporarily, not actually autoreleased.
+- Moving weak references skips the retain / release step.
+
+ARC requires the ability to interoperate perfectly with manual retain / release
+code, including the ability for non-ARC code to implement custom reference
+counting behaviour.  If an object implements -_ARCCompliantRetainRelease, then
+it is advertising that its retain, release, and autorelease implementations are
+ARC-compatible.  These methods may be called explicitly in non-ARC code, but
+will not be called from ARC.
+
+ARC moves autorelease pools into the runtime.  If NSAutoreleasePool exists and
+does not implement a -_ARCCompatibleAutoreleasePool method, then it will be
+used directly.  If it does not exist, ARC will implement its own autorelease
+pools.  If it exists and does implement -_ARCCompatibleAutoreleasePool then it
+must call objc_autoreleasePoolPush() and objc_autoreleasePoolPop() to manage
+autoreleased object storage and call objc_autorelease() in its -addObject:
+method.
diff --git a/third_party/libobjc/Test/BlockImpTest.m b/third_party/libobjc/Test/BlockImpTest.m
new file mode 100644
index 0000000000000000000000000000000000000000..f43a040f38e909162b3444ee89a7514ea7df72fa
--- /dev/null
+++ b/third_party/libobjc/Test/BlockImpTest.m
@@ -0,0 +1,54 @@
+#include <objc/runtime.h>
+#include <objc/blocks_runtime.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+struct big
+{
+	int a, b, c, d, e;
+};
+
+@interface Foo @end
+@implementation Foo @end
+@interface Foo (Dynamic)
++(int)count: (int)i;
++(struct big)sret;
+@end
+
+int main(void)
+{
+	__block int b = 0;
+	void* blk = ^(id self, int a) {
+		b += a; 
+		return b; };
+	blk = Block_copy(blk);
+	IMP imp = imp_implementationWithBlock(blk);
+	char *type = block_copyIMPTypeEncoding_np(blk);
+	assert(NULL != type);
+	class_addMethod((objc_getMetaClass("Foo")), @selector(count:), imp, type);
+	free(type);
+	assert(2 == [Foo count: 2]);
+	assert(4 == [Foo count: 2]);
+	assert(6 == [Foo count: 2]);
+	assert(imp_getBlock(imp) == (blk));
+	imp_removeBlock(blk);
+
+	blk = ^(id self) {
+		struct big b = {1, 2, 3, 4, 5};
+		return b;
+	};
+	imp = imp_implementationWithBlock(blk);
+	assert(imp && "Can't make sret IMP");
+	type = block_copyIMPTypeEncoding_np(blk);
+	assert(NULL != type);
+	class_addMethod((objc_getMetaClass("Foo")), @selector(sret), imp, type);
+	free(type);
+	struct big s = [Foo sret];
+	assert(s.a == 1);
+	assert(s.b == 2);
+	assert(s.c == 3);
+	assert(s.d == 4);
+	assert(s.e == 5);
+	return 0;
+}
diff --git a/third_party/libobjc/Test/GNUmakefile b/third_party/libobjc/Test/GNUmakefile
new file mode 100644
index 0000000000000000000000000000000000000000..94e24fdc1533b49ec334e38c1b26cd5d893676d1
--- /dev/null
+++ b/third_party/libobjc/Test/GNUmakefile
@@ -0,0 +1,8 @@
+include $(GNUSTEP_MAKEFILES)/common.make
+
+TOOL_NAME = RuntimeTest
+
+RuntimeTest_OBJC_FILES=\
+	RuntimeTest.m
+
+include $(GNUSTEP_MAKEFILES)/tool.make
diff --git a/third_party/libobjc/Test/PropertyIntrospectionTest.m b/third_party/libobjc/Test/PropertyIntrospectionTest.m
new file mode 100644
index 0000000000000000000000000000000000000000..bcf82b74467b61269fcf2ba08a067d11313056ff
--- /dev/null
+++ b/third_party/libobjc/Test/PropertyIntrospectionTest.m
@@ -0,0 +1,36 @@
+#import <objc/runtime.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+@interface Foo
+@property (getter=bar, setter=setBar:, nonatomic, copy) id foo;
+@end
+@interface Foo(Bar)
+-(id)bar;
+-(void)setBar:(id)b;
+@end 
+@implementation Foo
+@synthesize  foo;
+@end
+
+int main(void)
+{
+	objc_property_t p = class_getProperty(objc_getClass("Foo"), "foo");
+	unsigned int count;
+	objc_property_attribute_t *l = property_copyAttributeList(p, &count);
+	for (unsigned int i=0 ; i<count ; i++)
+	{
+		switch (l[i].name[0])
+		{
+			case 'T': assert(0==strcmp(l[i].value, "@")); break;
+			case 'C': assert(0==strcmp(l[i].value, "")); break;
+			case 'N': assert(0==strcmp(l[i].value, "")); break;
+			case 'G': assert(0==strcmp(l[i].value, "bar")); break;
+			case 'S': assert(0==strcmp(l[i].value, "setBar:")); break;
+			case 'B': assert(0==strcmp(l[i].value, "foo")); break;
+		}
+	}
+	assert(0 == property_copyAttributeList(0, &count));
+	return 0;
+}
diff --git a/third_party/libobjc/Test/ProtocolCreation.m b/third_party/libobjc/Test/ProtocolCreation.m
new file mode 100644
index 0000000000000000000000000000000000000000..204021d88f33ede34c8f7ec921dd44f9e2ae4a3a
--- /dev/null
+++ b/third_party/libobjc/Test/ProtocolCreation.m
@@ -0,0 +1,28 @@
+#import <objc/runtime.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+@protocol Test2 @end
+
+int main(void)
+{
+	Protocol *p = objc_allocateProtocol("Test");
+	protocol_addMethodDescription(p, @selector(someMethod), "@:", YES, NO);
+	assert(objc_getProtocol("Test2"));
+	protocol_addProtocol(p, objc_getProtocol("Test2"));
+	objc_property_attribute_t attrs[] = { {"T", "@" } };
+	protocol_addProperty(p, "foo", attrs, 1, YES, YES);
+	objc_registerProtocol(p);
+	Protocol *p1 = objc_getProtocol("Test");
+	assert(p == p1);
+	struct objc_method_description d = protocol_getMethodDescription(p1, @selector(someMethod), YES, NO);
+	assert(strcmp(sel_getName(d.name), "someMethod") == 0);
+	assert(strcmp((d.types), "@:") == 0);
+	assert(protocol_conformsToProtocol(p1, objc_getProtocol("Test2")));
+	unsigned int count;
+	objc_property_t *props = protocol_copyPropertyList(p1, &count);
+	assert(count == 1);
+	assert(strcmp("T@,Vfoo", property_getAttributes(*props)) == 0);
+	return 0;
+}
diff --git a/third_party/libobjc/Test/RuntimeTest.m b/third_party/libobjc/Test/RuntimeTest.m
new file mode 100644
index 0000000000000000000000000000000000000000..83eeb05b3bde58ca4684f37a8b041b3a9cf2c3d9
--- /dev/null
+++ b/third_party/libobjc/Test/RuntimeTest.m
@@ -0,0 +1,298 @@
+#import <Foundation/Foundation.h>
+#include <objc/runtime.h>
+
+static int exitStatus = 0;
+
+static void _test(BOOL X, char *expr, int line)
+{
+  if (!X)
+  {
+    exitStatus = 1;
+    fprintf(stderr, "ERROR: Test failed: '%s' on %s:%d\n", expr, __FILE__, line);
+  }
+}
+#define test(X) _test(X, #X, __LINE__)
+
+static int stringsEqual(const char *a, const char *b)
+{
+  return 0 == strcmp(a,b);
+}
+
+
+
+@interface Foo : NSObject
+{
+  id a;
+}
+- (void) aMethod;
++ (void) aMethod;
+- (int) manyTypes;
+- (void) synchronizedCode;
++ (void) synchronizedCode;
++ (id) shared;
+- (BOOL) basicThrowAndCatchException;
+@end
+
+@interface Bar : Foo
+{
+  id b;
+}
+- (void) anotherMethod;
++ (void) anotherMethod;
+- (id) manyTypes;
+- (id) aBool: (BOOL)d andAnInt: (int) w;
+@end
+
+
+@implementation Foo
+- (void) aMethod
+{
+}
++ (void) aMethod
+{
+}
+- (int) manyTypes
+{
+  return YES;
+}
+- (void) synchronizedCode
+{
+	@synchronized(self) { [[self class] synchronizedCode]; }
+}
++ (void) synchronizedCode
+{
+	@synchronized(self) { }
+}
++ (id) shared
+{
+	@synchronized(self) { }
+	return nil;
+}
+- (void) throwException
+{
+	@throw [NSException exceptionWithName: @"RuntimeTestException" reason: @"" userInfo: nil];
+}
+- (BOOL) basicThrowAndCatchException
+{
+	@try
+	{
+		[self throwException];
+	}
+	@catch (NSException *e)
+	{
+		NSLog(@"Caught %@", e);
+	}
+	@finally
+	{
+		return YES;
+	}
+	return NO;
+}
+@end
+
+@implementation Bar
+- (void) anotherMethod
+{
+}
++ (void) anotherMethod
+{
+}
+- (id) manyTypes
+{
+  return @"Hello";
+}
+- (id) aBool: (BOOL)d andAnInt: (int) w
+{
+  return @"Hello";
+}
+@end
+
+
+void testInvalidArguments()
+{
+  test(NO == class_conformsToProtocol([NSObject class], NULL));
+  test(NO == class_conformsToProtocol(Nil, NULL));
+  test(NO == class_conformsToProtocol(Nil, @protocol(NSCoding)));
+  test(NULL == class_copyIvarList(Nil, NULL));
+  test(NULL == class_copyMethodList(Nil, NULL));
+  test(NULL == class_copyPropertyList(Nil, NULL));
+  test(NULL == class_copyProtocolList(Nil, NULL));
+  test(nil == class_createInstance(Nil, 0));
+  test(0 == class_getVersion(Nil));
+  test(NO == class_isMetaClass(Nil));
+  test(Nil == class_getSuperclass(Nil));
+
+  test(NULL == method_getName(NULL));
+  test(NULL == method_copyArgumentType(NULL, 0));
+  test(NULL == method_copyReturnType(NULL));
+  method_exchangeImplementations(NULL, NULL);
+  test((IMP)NULL == method_setImplementation(NULL, (IMP)NULL));
+  test((IMP)NULL == method_getImplementation(NULL));
+  method_getArgumentType(NULL, 0, NULL, 0);
+  test(0 == method_getNumberOfArguments(NULL));
+  test(NULL == method_getTypeEncoding(NULL));
+  method_getReturnType(NULL, NULL, 0);
+
+  test(NULL == ivar_getName(NULL));
+  test(0 == ivar_getOffset(NULL));
+  test(NULL == ivar_getTypeEncoding(NULL));
+
+  test(nil == objc_getProtocol(NULL));
+
+  test(stringsEqual("<null selector>", sel_getName((SEL)0)));
+  test((SEL)0 == sel_getUid(NULL));
+  test(0 != sel_getUid("")); // the empty string is permitted as a selector
+  test(stringsEqual("", sel_getName(sel_getUid(""))));
+  test(YES == sel_isEqual((SEL)0, (SEL)0));
+
+  //test(NULL == property_getName(NULL));
+
+  printf("testInvalidArguments() ran\n");
+}
+
+void testAMethod(Method m)
+{
+  test(NULL != m);
+  test(stringsEqual("aMethod", sel_getName(method_getName(m))));
+
+  printf("testAMethod() ran\n");
+}
+
+void testGetMethod()
+{
+  testAMethod(class_getClassMethod([Bar class], @selector(aMethod)));
+  testAMethod(class_getClassMethod([Bar class], sel_getUid("aMethod")));
+
+  printf("testGetMethod() ran\n");
+}
+
+void testProtocols()
+{
+  test(protocol_isEqual(@protocol(NSCoding), objc_getProtocol("NSCoding")));
+
+  printf("testProtocols() ran\n");
+}
+
+void testMultiTypedSelector()
+{
+  test(sel_isEqual(@selector(manyTypes),sel_getUid("manyTypes")));
+  test(@selector(manyTypes) == sel_getUid("manyTypes"));
+
+  Method intMethod = class_getInstanceMethod([Foo class], @selector(manyTypes));
+  Method idMethod = class_getInstanceMethod([Bar class], @selector(manyTypes));
+
+  test(method_getName(intMethod) == @selector(manyTypes));
+  test(method_getName(idMethod) == @selector(manyTypes));
+
+  test(sel_isEqual(method_getName(intMethod), @selector(manyTypes)));
+  test(sel_isEqual(method_getName(idMethod), @selector(manyTypes)));
+
+  char ret[10];
+  method_getReturnType(intMethod, ret, 10);
+  test(stringsEqual(ret, "i"));
+  method_getReturnType(idMethod, ret, 10);
+  test(stringsEqual(ret, "@"));
+
+  printf("testMultiTypedSelector() ran\n");
+}
+
+void testClassHierarchy()
+{
+  Class nsProxy = objc_getClass("NSProxy");
+  Class nsObject = objc_getClass("NSObject");
+  Class nsProxyMeta = object_getClass(nsProxy);
+  Class nsObjectMeta = object_getClass(nsObject);
+
+  test(object_getClass(nsProxyMeta) == nsProxyMeta);
+  test(object_getClass(nsObjectMeta) == nsObjectMeta);
+
+  test(Nil == class_getSuperclass(nsProxy));
+  test(Nil == class_getSuperclass(nsObject));
+
+  test(nsObject == class_getSuperclass(nsObjectMeta));
+  test(nsProxy == class_getSuperclass(nsProxyMeta));
+  printf("testClassHierarchy() ran\n");
+}
+
+void testAllocateClass()
+{
+  Class newClass = objc_allocateClassPair(objc_lookUpClass("NSObject"), "UserAllocated", 0);
+  test(Nil != newClass);
+  // class_getSuperclass() will call objc_resolve_class().
+  // Although we have not called objc_registerClassPair() yet, this works with
+  // the Apple runtime and GNUstep Base relies on this behavior in
+  // GSObjCMakeClass().
+  test(objc_lookUpClass("NSObject") == class_getSuperclass(newClass));
+  printf("testAllocateClass() ran\n");
+}
+
+void testSynchronized()
+{
+  Foo *foo = [Foo new];
+  printf("Enter synchronized code\n");
+  [foo synchronizedCode];
+  [foo release];
+  [Foo shared];
+  printf("testSynchronized() ran\n");
+}
+
+void testExceptions()
+{
+  Foo *foo = [Foo new];
+  test([foo basicThrowAndCatchException]);
+  [foo release];
+  printf("testExceptions() ran\n");
+
+}
+
+void testRegisterAlias()
+{
+  class_registerAlias_np([NSObject class], "AliasObject");
+  test([NSObject class] == objc_getClass("AliasObject"));
+  printf("testRegisterAlias() ran\n");
+}
+
+@interface SlowInit1
++ (void)doNothing;
+@end
+@interface SlowInit2
++ (void)doNothing;
+@end
+@implementation SlowInit1
++ (void)initialize
+{
+	sleep(1);
+	[SlowInit2 doNothing];
+}
++ (void)doNothing {}
+@end
+static int initCount;
+@implementation SlowInit1
++ (void)initialize
+{
+	sleep(1);
+	__sync_fetch_and_add(&initCount, 1);
+}
++ (void)doNothing {}
+@end
+
+
+
+int main (int argc, const char * argv[])
+{
+  testInvalidArguments();
+  testGetMethod();
+  testProtocols();
+  testMultiTypedSelector();
+  testClassHierarchy();
+  testAllocateClass();
+  printf("Instance of NSObject: %p\n", class_createInstance([NSObject class], 0));
+
+  NSAutoreleasePool *pool = [NSAutoreleasePool new];
+  testSynchronized();
+  testExceptions();
+  testRegisterAlias();
+  [pool release];
+
+  return exitStatus;
+}
diff --git a/third_party/libobjc/Test/RuntimeTest.xcodeproj/project.pbxproj b/third_party/libobjc/Test/RuntimeTest.xcodeproj/project.pbxproj
new file mode 100644
index 0000000000000000000000000000000000000000..29fc1066624badb2dbb6e754c615fc74501016d1
--- /dev/null
+++ b/third_party/libobjc/Test/RuntimeTest.xcodeproj/project.pbxproj
@@ -0,0 +1,203 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 45;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		8DD76F9A0486AA7600D96B5E /* RuntimeTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* RuntimeTest.m */; settings = {ATTRIBUTES = (); }; };
+		8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		8DD76F9E0486AA7600D96B5E /* CopyFiles */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 8;
+			dstPath = /usr/share/man/man1/;
+			dstSubfolderSpec = 0;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 1;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+		08FB7796FE84155DC02AAC07 /* RuntimeTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RuntimeTest.m; sourceTree = "<group>"; };
+		08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
+		8DD76FA10486AA7600D96B5E /* RuntimeTest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = RuntimeTest; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		8DD76F9B0486AA7600D96B5E /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		08FB7794FE84155DC02AAC07 /* RuntimeTest */ = {
+			isa = PBXGroup;
+			children = (
+				08FB7795FE84155DC02AAC07 /* Source */,
+				08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
+				1AB674ADFE9D54B511CA2CBB /* Products */,
+			);
+			name = RuntimeTest;
+			sourceTree = "<group>";
+		};
+		08FB7795FE84155DC02AAC07 /* Source */ = {
+			isa = PBXGroup;
+			children = (
+				08FB7796FE84155DC02AAC07 /* RuntimeTest.m */,
+			);
+			name = Source;
+			sourceTree = "<group>";
+		};
+		08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = {
+			isa = PBXGroup;
+			children = (
+				08FB779EFE84155DC02AAC07 /* Foundation.framework */,
+			);
+			name = "External Frameworks and Libraries";
+			sourceTree = "<group>";
+		};
+		1AB674ADFE9D54B511CA2CBB /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				8DD76FA10486AA7600D96B5E /* RuntimeTest */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		8DD76F960486AA7600D96B5E /* RuntimeTest */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "RuntimeTest" */;
+			buildPhases = (
+				8DD76F990486AA7600D96B5E /* Sources */,
+				8DD76F9B0486AA7600D96B5E /* Frameworks */,
+				8DD76F9E0486AA7600D96B5E /* CopyFiles */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = RuntimeTest;
+			productInstallPath = "$(HOME)/bin";
+			productName = RuntimeTest;
+			productReference = 8DD76FA10486AA7600D96B5E /* RuntimeTest */;
+			productType = "com.apple.product-type.tool";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		08FB7793FE84155DC02AAC07 /* Project object */ = {
+			isa = PBXProject;
+			buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "RuntimeTest" */;
+			compatibilityVersion = "Xcode 3.1";
+			hasScannedForEncodings = 1;
+			mainGroup = 08FB7794FE84155DC02AAC07 /* RuntimeTest */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				8DD76F960486AA7600D96B5E /* RuntimeTest */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+		8DD76F990486AA7600D96B5E /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				8DD76F9A0486AA7600D96B5E /* RuntimeTest.m in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		1DEB927508733DD40010E9CD /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				COPY_PHASE_STRIP = NO;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_FIX_AND_CONTINUE = YES;
+				GCC_MODEL_TUNING = G5;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				INSTALL_PATH = /usr/local/bin;
+				PRODUCT_NAME = RuntimeTest;
+			};
+			name = Debug;
+		};
+		1DEB927608733DD40010E9CD /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				GCC_MODEL_TUNING = G5;
+				INSTALL_PATH = /usr/local/bin;
+				PRODUCT_NAME = RuntimeTest;
+			};
+			name = Release;
+		};
+		1DEB927908733DD40010E9CD /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				ONLY_ACTIVE_ARCH = YES;
+				PREBINDING = NO;
+				SDKROOT = macosx10.6;
+			};
+			name = Debug;
+		};
+		1DEB927A08733DD40010E9CD /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				PREBINDING = NO;
+				SDKROOT = macosx10.6;
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "RuntimeTest" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				1DEB927508733DD40010E9CD /* Debug */,
+				1DEB927608733DD40010E9CD /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "RuntimeTest" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				1DEB927908733DD40010E9CD /* Debug */,
+				1DEB927A08733DD40010E9CD /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
+}
diff --git a/third_party/libobjc/Test/objc_msgSend.m b/third_party/libobjc/Test/objc_msgSend.m
new file mode 100644
index 0000000000000000000000000000000000000000..ff179cda9c3471a413d726c03e2330a4f6900463
--- /dev/null
+++ b/third_party/libobjc/Test/objc_msgSend.m
@@ -0,0 +1,143 @@
+#include <time.h>
+#include <stdio.h>
+#include <objc/runtime.h>
+#include <assert.h>
+#include <string.h>
+#include <class.h>
+#include <stdarg.h>
+
+//#define assert(x) if (!(x)) { printf("Failed %d\n", __LINE__); }
+
+id objc_msgSend(id, SEL, ...);
+
+typedef struct { int a,b,c,d,e; } s;
+s objc_msgSend_stret(id, SEL, ...);
+@interface Fake
+- (int)izero;
+- (float)fzero;
+- (double)dzero;
+- (long double)ldzero;
+@end
+
+Class TestCls;
+@interface Test { id isa; }@end
+@implementation Test 
+- foo
+{
+	assert((id)1 == self);
+	assert(strcmp("foo", sel_getName(_cmd)) == 0);
+	return (id)0x42;
+}
++ foo
+{
+	assert(TestCls == self);
+	assert(strcmp("foo", sel_getName(_cmd)) == 0);
+	return (id)0x42;
+}
++ (s)sret
+{
+	assert(TestCls == self);
+	assert(strcmp("sret", sel_getName(_cmd)) == 0);
+	s st = {1,2,3,4,5};
+	return st;
+}
+- (s)sret
+{
+	assert((id)3 == self);
+	assert(strcmp("sret", sel_getName(_cmd)) == 0);
+	s st = {1,2,3,4,5};
+	return st;
+}
++ (void)printf: (const char*)str, ...
+{
+	va_list ap;
+	char *s;
+
+	va_start(ap, str);
+
+	vasprintf(&s, str, ap);
+	va_end(ap);
+	//fprintf(stderr, "String: '%s'\n", s);
+	assert(strcmp(s, "Format string 42 42.000000\n") ==0);
+}
++ (void)initialize
+{
+	[self printf: "Format %s %d %f%c", "string", 42, 42.0, '\n'];
+	@throw self;
+}
++ nothing { return 0; }
+@end
+int main(void)
+{
+	TestCls = objc_getClass("Test");
+	int exceptionThrown = 0;
+	@try {
+		objc_msgSend(TestCls, @selector(foo));
+	} @catch (id e)
+	{
+		assert((TestCls == e) && "Exceptions propagate out of +initialize");
+		exceptionThrown = 1;
+	}
+	assert(exceptionThrown && "An exception was thrown");
+	assert((id)0x42 == objc_msgSend(TestCls, @selector(foo)));
+	objc_msgSend(TestCls, @selector(nothing));
+	objc_msgSend(TestCls, @selector(missing));
+	assert(0 == objc_msgSend(0, @selector(nothing)));
+	id a = objc_msgSend(objc_getClass("Test"), @selector(foo));
+	assert((id)0x42 == a);
+	a = objc_msgSend(TestCls, @selector(foo));
+	assert((id)0x42 == a);
+	assert(objc_registerSmallObjectClass_np(objc_getClass("Test"), 1));
+	a = objc_msgSend((id)01, @selector(foo));
+	assert((id)0x42 == a);
+	s ret = objc_msgSend_stret(TestCls, @selector(sret));
+	assert(ret.a == 1);
+	assert(ret.b == 2);
+	assert(ret.c == 3);
+	assert(ret.d == 4);
+	assert(ret.e == 5);
+	if (sizeof(id) == 8)
+	{
+		assert(objc_registerSmallObjectClass_np(objc_getClass("Test"), 3));
+		ret = objc_msgSend_stret((id)3, @selector(sret));
+		assert(ret.a == 1);
+		assert(ret.b == 2);
+		assert(ret.c == 3);
+		assert(ret.d == 4);
+		assert(ret.e == 5);
+	}
+	Fake *f = nil;
+	assert(0 == [f izero]);
+	assert(0 == [f dzero]);
+	assert(0 == [f ldzero]);
+	assert(0 == [f fzero]);
+#ifdef BENCHMARK
+	clock_t c1, c2;
+	c1 = clock();
+	for (int i=0 ; i<100000000 ; i++)
+	{
+		[TestCls nothing];
+	}
+	c2 = clock();
+	printf("Traditional message send took %f seconds. \n", 
+		((double)c2 - (double)c1) / (double)CLOCKS_PER_SEC);
+	c1 = clock();
+	for (int i=0 ; i<100000000 ; i++)
+	{
+		objc_msgSend(TestCls, @selector(nothing));
+	}
+	c2 = clock();
+	printf("objc_msgSend() message send took %f seconds. \n", 
+		((double)c2 - (double)c1) / (double)CLOCKS_PER_SEC);
+	IMP nothing = objc_msg_lookup(TestCls, @selector(nothing));
+	c1 = clock();
+	for (int i=0 ; i<100000000 ; i++)
+	{
+		nothing(TestCls, @selector(nothing));
+	}
+	c2 = clock();
+	printf("Direct IMP call took %f seconds. \n", 
+		((double)c2 - (double)c1) / (double)CLOCKS_PER_SEC);
+#endif
+	return 0;
+}
diff --git a/third_party/libobjc/abi_version.c b/third_party/libobjc/abi_version.c
new file mode 100644
index 0000000000000000000000000000000000000000..a75a3f5cc2816cb053ce6c5985e937804e63b4bd
--- /dev/null
+++ b/third_party/libobjc/abi_version.c
@@ -0,0 +1,143 @@
+#include "visibility.h"
+#include "objc/runtime.h"
+#include "module.h"
+#include "gc_ops.h"
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+/**
+ * The smallest ABI version number of loaded modules.
+ */
+static unsigned long min_loaded_version;
+/**
+ * The largest ABI version number of loaded modules.
+ */
+static unsigned long max_loaded_version;
+
+/**
+ * Structure defining the compatibility between Objective-C ABI versions.
+ */
+struct objc_abi_version
+{
+	/** Version of this ABI. */
+	unsigned long version;
+	/** Lowest ABI version that this is compatible with. */
+	unsigned long min_compatible_version;
+	/** Highest ABI version compatible with this. */
+	unsigned long max_compatible_version;
+	/** Size of the module structure for this ABI version. */
+	unsigned long module_size;
+};
+
+enum
+{
+	gcc_abi = 8,
+	gnustep_abi = 9,
+	gc_abi = 10
+};
+
+/**
+ * List of supported ABIs.
+ */
+static struct objc_abi_version known_abis[] =
+{
+	/* GCC ABI. */
+	{gcc_abi, gcc_abi, gnustep_abi, sizeof(struct objc_module_abi_8)},
+	/* Non-fragile ABI. */
+	{gnustep_abi, gcc_abi, gc_abi, sizeof(struct objc_module_abi_8)},
+	/* GC ABI.  Adds a field describing the GC mode. */
+	{gc_abi, gcc_abi, gc_abi, sizeof(struct objc_module_abi_10)}
+};
+
+static int known_abi_count =
+	(sizeof(known_abis) / sizeof(struct objc_abi_version));
+
+#define FAIL_IF(x, msg) do {\
+	if (x)\
+	{\
+		fprintf(stderr, "Objective-C ABI Error: %s while loading %s\n", msg, module->name);\
+		return NO;\
+	}\
+} while(0)
+
+PRIVATE enum objc_gc_mode current_gc_mode = GC_Optional;
+
+static BOOL endsWith(const char *string, const char *suffix)
+{
+	if (NULL == string) { return NO; }
+	char *interior = strstr(string, suffix);
+	return (interior && (strlen(suffix) == strlen(interior)));
+}
+
+PRIVATE BOOL objc_check_abi_version(struct objc_module_abi_8 *module)
+{
+	static int runtime_modules = 5;
+	// As a quick and ugly hack, skip these three tests for the .m files in the
+	// runtime.  They should (in theory, at least) be aware of the GC mode and
+	// behave accordingly.
+	if (runtime_modules > 0)
+	{
+		if (endsWith(module->name, "properties.m") ||
+		    endsWith(module->name, "associate.m") ||
+		    endsWith(module->name, "arc.m") ||
+		    endsWith(module->name, "blocks_runtime.m") ||
+		    endsWith(module->name, "Protocol2.m"))
+		{
+			runtime_modules--;
+			return YES;
+		}
+	}
+	unsigned long version = module->version;
+	unsigned long module_size = module->size;
+	enum objc_gc_mode gc_mode = (version < gc_abi) ? GC_None
+	                            : ((struct objc_module_abi_10*)module)->gc_mode;
+	struct objc_abi_version *v = NULL;
+	for (int i=0 ; i<known_abi_count ; i++)
+	{
+		if (known_abis[i].version == version)
+		{
+			v = &known_abis[i];
+			break;
+		}
+	}
+	FAIL_IF(NULL == v, "Unknown ABI version");
+	FAIL_IF((v->module_size != module_size), "Incorrect module size");
+	// Only check for ABI compatibility if 
+	if (min_loaded_version > 0)
+	{
+		FAIL_IF((v->min_compatible_version > min_loaded_version),
+				"Loading modules from incompatible ABIs");
+		FAIL_IF((v->max_compatible_version < max_loaded_version),
+				"Loading modules from incompatible ABIs");
+		if (min_loaded_version > version)
+		{
+			min_loaded_version = version;
+		}
+		if (max_loaded_version < version)
+		{
+			max_loaded_version = version;
+		}
+	}
+	else
+	{
+		min_loaded_version = version;
+		max_loaded_version = version;
+	}
+
+	// If we're currently in GC-optional mode, then fall to one side or the
+	// other if this module requires / doesn't support GC
+	if (current_gc_mode == GC_Optional)
+	{
+		current_gc_mode = gc_mode;
+		if (gc_mode == GC_Required)
+		{
+			enableGC(NO);
+		}
+	}
+	// We can't mix GC_None and GC_Required code, but we can mix any other
+	// combination
+	FAIL_IF((gc_mode == GC_Required) && (gc_mode != current_gc_mode),
+	        "Attempting to mix GC and non-GC code!");
+	return YES;
+}
diff --git a/third_party/libobjc/alias.h b/third_party/libobjc/alias.h
new file mode 100644
index 0000000000000000000000000000000000000000..edf5ef30addef130b0a73aa6cea877d9dbf7c2e8
--- /dev/null
+++ b/third_party/libobjc/alias.h
@@ -0,0 +1,27 @@
+/** Declaration of a helper function for getting class references from aliases.
+   Copyright (c) 2011 Free Software Foundation, Inc.
+
+   Written by:  Niels Grewe <niels.grewe@halbordnung.de>
+   Created: March 2011
+
+   Permission is hereby granted, free of charge, to any person obtaining a copy
+   of this software and associated documentation files (the "Software"), to deal
+   in the Software without restriction, including without limitation the rights
+   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+   copies of the Software, and to permit persons to whom the Software is
+   furnished to do so, subject to the following conditions:
+
+   The above copyright notice and this permission notice shall be included in
+   all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+   THE SOFTWARE.
+*/
+#include "objc/runtime.h"
+
+Class alias_getClass(const char *alias_name);
diff --git a/third_party/libobjc/alias_table.c b/third_party/libobjc/alias_table.c
new file mode 100644
index 0000000000000000000000000000000000000000..9fda1cd6df4cccd118f5402125a266c766ff25f2
--- /dev/null
+++ b/third_party/libobjc/alias_table.c
@@ -0,0 +1,126 @@
+/** A hash table for mapping compatibility aliases to classes.
+   Copyright (c) 2011 Free Software Foundation, Inc.
+
+   Written by:  Niels Grewe <niels.grewe@halbordnung.de>
+   Created: March 2011
+
+   Permission is hereby granted, free of charge, to any person obtaining a copy
+   of this software and associated documentation files (the "Software"), to deal
+   in the Software without restriction, including without limitation the rights
+   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+   copies of the Software, and to permit persons to whom the Software is
+   furnished to do so, subject to the following conditions:
+
+   The above copyright notice and this permission notice shall be included in
+   all copies or substantial portions of the Software.
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+   THE SOFTWARE.
+*/
+
+#include "visibility.h"
+#include "objc/runtime.h"
+#include "class.h"
+#include "lock.h"
+#include "string_hash.h"
+
+#include <stdlib.h>
+
+struct objc_alias
+{
+	const char* name;
+	Class class;
+};
+
+typedef struct objc_alias Alias;
+
+static int alias_compare(const char *name, const Alias alias)
+{
+	return string_compare(name, alias.name);
+}
+
+static int alias_hash(const Alias alias)
+{
+	return string_hash(alias.name);
+}
+static int alias_is_null(const Alias alias)
+{
+	return alias.name == NULL;
+}
+static Alias NullAlias;
+#define MAP_TABLE_NAME alias_table_internal
+#define MAP_TABLE_COMPARE_FUNCTION alias_compare
+#define MAP_TABLE_HASH_KEY string_hash
+#define MAP_TABLE_HASH_VALUE alias_hash
+#define MAP_TABLE_VALUE_TYPE struct objc_alias
+#define MAP_TABLE_VALUE_NULL alias_is_null
+#define MAP_TABLE_VALUE_PLACEHOLDER NullAlias
+
+#include "hash_table.h"
+
+static alias_table_internal_table *alias_table;
+
+PRIVATE void init_alias_table(void)
+{
+	alias_table_internal_initialize(&alias_table, 128);
+}
+
+
+static Alias alias_table_get_safe(const char *alias_name)
+{
+	return alias_table_internal_table_get(alias_table, alias_name);
+}
+
+
+Class alias_getClass(const char *alias_name)
+{
+	if (NULL == alias_name)
+	{
+		return NULL;
+	}
+
+	Alias alias = alias_table_get_safe(alias_name);
+
+	if (NULL == alias.name)
+	{
+		return NULL;
+	}
+
+	return alias.class;
+}
+
+PRIVATE void alias_table_insert(Alias alias)
+{
+	alias_table_internal_insert(alias_table, alias);
+}
+
+BOOL class_registerAlias_np(Class class, const char *alias)
+{
+	if ((NULL == alias) || (NULL == class))
+	{
+		return 0;
+	}
+
+	/*
+	 * If there already exists a matching alias, determine whether we the existing
+	 * alias is the correct one. Please note that objc_getClass() goes through the
+	 * alias lookup and will create the alias table if necessary.
+	 */
+	Class existingClass = (Class)objc_getClass(alias);
+	if (NULL != existingClass)
+	{
+		/*
+		 *  Return YES if the alias has already been registered for this very
+		 * class, and NO if the alias is already used for another class.
+		 */
+		return (class == existingClass);
+	}
+	Alias newAlias = { strdup(alias), class };
+	alias_table_insert(newAlias);
+	return 1;
+}
diff --git a/third_party/libobjc/arc.m b/third_party/libobjc/arc.m
new file mode 100644
index 0000000000000000000000000000000000000000..b8c6d7cfbe5801a380d939c6232287952de1930b
--- /dev/null
+++ b/third_party/libobjc/arc.m
@@ -0,0 +1,690 @@
+#include <stdlib.h>
+#include <assert.h>
+#import "stdio.h"
+#import "objc/runtime.h"
+#import "objc/blocks_runtime.h"
+#import "nsobject.h"
+#import "class.h"
+#import "selector.h"
+#import "visibility.h"
+#import "objc/hooks.h"
+#import "objc/objc-arc.h"
+#import "objc/blocks_runtime.h"
+
+#ifndef NO_PTHREADS
+#include <pthread.h>
+pthread_key_t ARCThreadKey;
+#endif
+
+extern void _NSConcreteMallocBlock;
+extern void _NSConcreteGlobalBlock;
+
+@interface NSAutoreleasePool
++ (Class)class;
++ (id)new;
+- (void)release;
+@end
+
+#define POOL_SIZE (4096 / sizeof(void*) - (2 * sizeof(void*)))
+/**
+ * Structure used for ARC-managed autorelease pools.  This structure should be
+ * exactly one page in size, so that it can be quickly allocated.  This does
+ * not correspond directly to an autorelease pool.  The 'pool' returned by
+ * objc_autoreleasePoolPush() may be an interior pointer to one of these
+ * structures.
+ */
+struct arc_autorelease_pool
+{
+	/**
+	 * Pointer to the previous autorelease pool structure in the chain.  Set
+	 * when pushing a new structure on the stack, popped during cleanup.
+	 */
+	struct arc_autorelease_pool *previous;
+	/**
+	 * The current insert point.
+	 */
+	id *insert;
+	/**
+	 * The remainder of the page, an array of object pointers.  
+	 */
+	id pool[POOL_SIZE];
+};
+
+struct arc_tls
+{
+	struct arc_autorelease_pool *pool;
+	id returnRetained;
+};
+
+static inline struct arc_tls* getARCThreadData(void)
+{
+#ifdef NO_PTHREADS
+	return NULL;
+#else
+	struct arc_tls *tls = pthread_getspecific(ARCThreadKey);
+	if (NULL == tls)
+	{
+		tls = calloc(sizeof(struct arc_tls), 1);
+		pthread_setspecific(ARCThreadKey, tls);
+	}
+	return tls;
+#endif
+}
+int count = 0;
+int poolCount = 0;
+static inline void release(id obj);
+
+/**
+ * Empties objects from the autorelease pool, stating at the head of the list
+ * specified by pool and continuing until it reaches the stop point.  If the stop point is NULL then 
+ */
+static void emptyPool(struct arc_tls *tls, id *stop)
+{
+	struct arc_autorelease_pool *stopPool = NULL;
+	if (NULL != stop)
+	{
+		stopPool = tls->pool;
+		while (1)
+		{
+			// Invalid stop location
+			if (NULL == stopPool)
+			{
+				return;
+			}
+			// NULL is the placeholder for the top-level pool
+			if (NULL == stop && stopPool->previous == NULL)
+			{
+				break;
+			}
+			// Stop location was found in this pool
+			if ((stop >= stopPool->pool) && (stop < &stopPool->pool[POOL_SIZE]))
+			{
+				break;
+			}
+			stopPool = stopPool->previous;
+		}
+	}
+	while (tls->pool != stopPool)
+	{
+		while (tls->pool->insert > tls->pool->pool)
+		{
+			tls->pool->insert--;
+			// This may autorelease some other objects, so we have to work in
+			// the case where the autorelease pool is extended during a -release.
+			release(*tls->pool->insert);
+			count--;
+		}
+		void *old = tls->pool;
+		tls->pool = tls->pool->previous;
+		free(old);
+	}
+	if (NULL != tls->pool)
+	{
+		while ((stop == NULL || (tls->pool->insert > stop)) &&
+		       (tls->pool->insert > tls->pool->pool))
+		{
+			tls->pool->insert--;
+			count--;
+			release(*tls->pool->insert);
+		}
+	}
+	//fprintf(stderr, "New insert: %p.  Stop: %p\n", tls->pool->insert, stop);
+}
+
+static void cleanupPools(struct arc_tls* tls)
+{
+	struct arc_autorelease_pool *pool = tls->pool;
+	if (tls->returnRetained)
+	{
+		release(tls->returnRetained);
+		tls->returnRetained = nil;
+	}
+	while(NULL != pool)
+	{
+		emptyPool(tls, NULL);
+		assert(NULL == tls->pool);
+	}
+	if (tls->returnRetained)
+	{
+		cleanupPools(tls);
+	}
+	free(tls);
+}
+
+
+static Class AutoreleasePool;
+static IMP NewAutoreleasePool;
+static IMP DeleteAutoreleasePool;
+static IMP AutoreleaseAdd;
+
+extern BOOL FastARCRetain;
+extern BOOL FastARCRelease;
+extern BOOL FastARCAutorelease;
+
+static BOOL useARCAutoreleasePool;
+
+static inline id retain(id obj)
+{
+	if (isSmallObject(obj)) { return obj; }
+	Class cls = obj->isa;
+	if ((Class)&_NSConcreteMallocBlock == cls)
+	{
+		return Block_copy(obj);
+	}
+	if (objc_test_class_flag(cls, objc_class_flag_fast_arc))
+	{
+		intptr_t *refCount = ((intptr_t*)obj) - 1;
+		__sync_add_and_fetch(refCount, 1);
+		return obj;
+	}
+	return [obj retain];
+}
+
+static inline void release(id obj)
+{
+	if (isSmallObject(obj)) { return; }
+	Class cls = obj->isa;
+	if (objc_test_class_flag(cls, objc_class_flag_fast_arc))
+	{
+		intptr_t *refCount = ((intptr_t*)obj) - 1;
+		if (__sync_sub_and_fetch(refCount, 1) < 0)
+		{
+			objc_delete_weak_refs(obj);
+			[obj dealloc];
+		}
+		return;
+	}
+	[obj release];
+}
+
+static inline void initAutorelease(void)
+{
+	if (Nil == AutoreleasePool)
+	{
+		AutoreleasePool = objc_getRequiredClass("NSAutoreleasePool");
+		if (Nil == AutoreleasePool)
+		{
+			useARCAutoreleasePool = YES;
+		}
+		else
+		{
+			[AutoreleasePool class];
+			useARCAutoreleasePool = class_respondsToSelector(AutoreleasePool,
+			                                                 SELECTOR(_ARCCompatibleAutoreleasePool));
+			NewAutoreleasePool = class_getMethodImplementation(object_getClass(AutoreleasePool),
+			                                                   SELECTOR(new));
+			DeleteAutoreleasePool = class_getMethodImplementation(AutoreleasePool,
+			                                                      SELECTOR(release));
+			AutoreleaseAdd = class_getMethodImplementation(object_getClass(AutoreleasePool),
+			                                               SELECTOR(addObject:));
+		}
+	}
+}
+
+static inline id autorelease(id obj)
+{
+	//fprintf(stderr, "Autoreleasing %p\n", obj);
+	if (useARCAutoreleasePool)
+	{
+		struct arc_tls *tls = getARCThreadData();
+		if (NULL != tls)
+		{
+			struct arc_autorelease_pool *pool = tls->pool;
+			if (NULL == pool || (pool->insert >= &pool->pool[POOL_SIZE]))
+			{
+				pool = calloc(sizeof(struct arc_autorelease_pool), 1);
+				pool->previous = tls->pool;
+				pool->insert = pool->pool;
+				tls->pool = pool;
+			}
+			count++;
+			*pool->insert = obj;
+			pool->insert++;
+			return obj;
+		}
+	}
+	if (objc_test_class_flag(classForObject(obj), objc_class_flag_fast_arc))
+	{
+		initAutorelease();
+		if (0 != AutoreleaseAdd)
+		{
+			AutoreleaseAdd(AutoreleasePool, SELECTOR(addObject:), obj);
+		}
+		return obj;
+	}
+	return [obj autorelease];
+}
+
+unsigned long objc_arc_autorelease_count_np(void)
+{
+	struct arc_tls* tls = getARCThreadData();
+	unsigned long count = 0;
+	if (!tls) { return 0; }
+
+	for (struct arc_autorelease_pool *pool=tls->pool ;
+	     NULL != pool ;
+	     pool = pool->previous)
+	{
+		count += (((intptr_t)pool->insert) - ((intptr_t)pool->pool)) / sizeof(id);
+	}
+	return count;
+}
+unsigned long objc_arc_autorelease_count_for_object_np(id obj)
+{
+	struct arc_tls* tls = getARCThreadData();
+	unsigned long count = 0;
+	if (!tls) { return 0; }
+
+	for (struct arc_autorelease_pool *pool=tls->pool ;
+	     NULL != pool ;
+	     pool = pool->previous)
+	{
+		for (id* o = pool->insert-1 ; o >= pool->pool ; o--)
+		{
+			if (*o == obj)
+			{
+				count++;
+			}
+		}
+	}
+	return count;
+}
+
+
+void *objc_autoreleasePoolPush(void)
+{
+	initAutorelease();
+	struct arc_tls* tls = getARCThreadData();
+	// If there is an object in the return-retained slot, then we need to
+	// promote it to the real autorelease pool BEFORE pushing the new
+	// autorelease pool.  If we don't, then it may be prematurely autoreleased.
+	if ((NULL != tls) && (nil != tls->returnRetained))
+	{
+		autorelease(tls->returnRetained);
+		tls->returnRetained = nil;
+	}
+	if (useARCAutoreleasePool)
+	{
+		if (NULL != tls)
+		{
+			struct arc_autorelease_pool *pool = tls->pool;
+			if (NULL == pool || (pool->insert >= &pool->pool[POOL_SIZE]))
+			{
+				pool = calloc(sizeof(struct arc_autorelease_pool), 1);
+				pool->previous = tls->pool;
+				pool->insert = pool->pool;
+				tls->pool = pool;
+			}
+			// If there is no autorelease pool allocated for this thread, then
+			// we lazily allocate one the first time something is autoreleased.
+			return (NULL != tls->pool) ? tls->pool->insert : NULL;
+		}
+	}
+	initAutorelease();
+	if (0 == NewAutoreleasePool) { return NULL; }
+	return NewAutoreleasePool(AutoreleasePool, SELECTOR(new));
+}
+void objc_autoreleasePoolPop(void *pool)
+{
+	if (useARCAutoreleasePool)
+	{
+		struct arc_tls* tls = getARCThreadData();
+		if (NULL != tls)
+		{
+			if (NULL != tls->pool)
+			{
+				emptyPool(tls, pool);
+			}
+			return;
+		}
+	}
+	DeleteAutoreleasePool(pool, SELECTOR(release));
+	struct arc_tls* tls = getARCThreadData();
+	if (tls && tls->returnRetained)
+	{
+		release(tls->returnRetained);
+		tls->returnRetained = nil;
+	}
+}
+
+id objc_autorelease(id obj)
+{
+	if (nil != obj)
+	{
+		obj = autorelease(obj);
+	}
+	return obj;
+}
+
+id objc_autoreleaseReturnValue(id obj)
+{
+	if (!useARCAutoreleasePool) 
+	{
+		struct arc_tls* tls = getARCThreadData();
+		if (NULL != tls)
+		{
+			objc_autorelease(tls->returnRetained);
+			tls->returnRetained = obj;
+			return obj;
+		}
+	}
+	return objc_autorelease(obj);
+}
+
+id objc_retainAutoreleasedReturnValue(id obj)
+{
+	// If the previous object was released  with objc_autoreleaseReturnValue()
+	// just before return, then it will not have actually been autoreleased.
+	// Instead, it will have been stored in TLS.  We just remove it from TLS
+	// and undo the fake autorelease.
+	//
+	// If the object was not returned with objc_autoreleaseReturnValue() then
+	// we actually autorelease the fake object. and then retain the argument.
+	// In tis case, this is equivalent to objc_retain().
+	struct arc_tls* tls = getARCThreadData();
+	if (NULL != tls)
+	{
+		// If we're using our own autorelease pool, just pop the object from the top
+		if (useARCAutoreleasePool)
+		{
+			if ((NULL != tls->pool) &&
+			    (*(tls->pool->insert-1) == obj))
+			{
+				tls->pool->insert--;
+				return obj;
+			}
+		}
+		else if (obj == tls->returnRetained)
+		{
+			tls->returnRetained = NULL;
+			return obj;
+		}
+	}
+	return objc_retain(obj);
+}
+
+id objc_retain(id obj)
+{
+	if (nil == obj) { return nil; }
+	return retain(obj);
+}
+
+id objc_retainAutorelease(id obj)
+{
+	return objc_autorelease(objc_retain(obj));
+}
+
+id objc_retainAutoreleaseReturnValue(id obj)
+{
+	if (nil == obj) { return obj; }
+	return objc_autoreleaseReturnValue(retain(obj));
+}
+
+
+id objc_retainBlock(id b)
+{
+	return _Block_copy(b);
+}
+
+void objc_release(id obj)
+{
+	if (nil == obj) { return; }
+	release(obj);
+}
+
+id objc_storeStrong(id *addr, id value)
+{
+	value = objc_retain(value);
+	id oldValue = *addr;
+	*addr = value;
+	objc_release(oldValue);
+	return value;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Weak references
+////////////////////////////////////////////////////////////////////////////////
+
+typedef struct objc_weak_ref
+{
+	id obj;
+	id *ref[4];
+	struct objc_weak_ref *next;
+} WeakRef;
+
+
+static int weak_ref_compare(const id obj, const WeakRef weak_ref)
+{
+	return obj == weak_ref.obj;
+}
+
+static uint32_t ptr_hash(const void *ptr)
+{
+	// Bit-rotate right 4, since the lowest few bits in an object pointer will
+	// always be 0, which is not so useful for a hash value
+	return ((uintptr_t)ptr >> 4) | ((uintptr_t)ptr << ((sizeof(id) * 8) - 4));
+}
+static int weak_ref_hash(const WeakRef weak_ref)
+{
+	return ptr_hash(weak_ref.obj);
+}
+static int weak_ref_is_null(const WeakRef weak_ref)
+{
+	return weak_ref.obj == NULL;
+}
+const static WeakRef NullWeakRef;
+#define MAP_TABLE_NAME weak_ref
+#define MAP_TABLE_COMPARE_FUNCTION weak_ref_compare
+#define MAP_TABLE_HASH_KEY ptr_hash
+#define MAP_TABLE_HASH_VALUE weak_ref_hash
+#define MAP_TABLE_HASH_VALUE weak_ref_hash
+#define MAP_TABLE_VALUE_TYPE struct objc_weak_ref
+#define MAP_TABLE_VALUE_NULL weak_ref_is_null
+#define MAP_TABLE_VALUE_PLACEHOLDER NullWeakRef
+#define MAP_TABLE_ACCESS_BY_REFERENCE 1
+#define MAP_TABLE_SINGLE_THREAD 1
+#define MAP_TABLE_NO_LOCK 1
+
+#include "hash_table.h"
+
+static weak_ref_table *weakRefs;
+mutex_t weakRefLock;
+
+PRIVATE void init_arc(void)
+{
+	weak_ref_initialize(&weakRefs, 128);
+	INIT_LOCK(weakRefLock);
+#ifndef NO_PTHREADS
+	pthread_key_create(&ARCThreadKey, (void(*)(void*))cleanupPools);
+#endif
+}
+
+void* block_load_weak(void *block);
+
+id objc_storeWeak(id *addr, id obj)
+{
+	id old = *addr;
+	LOCK_FOR_SCOPE(&weakRefLock);
+	if (nil != old)
+	{
+		WeakRef *oldRef = weak_ref_table_get(weakRefs, old);
+		while (NULL != oldRef)
+		{
+			for (int i=0 ; i<4 ; i++)
+			{
+				if (oldRef->ref[i] == addr)
+				{
+					oldRef->ref[i] = 0;
+					oldRef = 0;
+					break;
+				}
+			}
+			oldRef = oldRef->next;
+		}
+	}
+	if (nil == obj)
+	{
+		*addr = obj;
+		return nil;
+	}
+	Class cls = classForObject(obj);
+	if (&_NSConcreteGlobalBlock == cls)
+	{
+		// If this is a global block, it's never deallocated, so secretly make
+		// this a strong reference
+		// TODO: We probably also want to do the same for constant strings and
+		// classes.
+		*addr = obj;
+		return obj;
+	}
+	if (&_NSConcreteMallocBlock == cls)
+	{
+		obj = block_load_weak(obj);
+	}
+	else if (objc_test_class_flag(cls, objc_class_flag_fast_arc))
+	{
+		if ((*(((intptr_t*)obj) - 1)) < 0)
+		{
+			return nil;
+		}
+	}
+	else
+	{
+		obj = _objc_weak_load(obj);
+	}
+	if (nil != obj)
+	{
+		WeakRef *ref = weak_ref_table_get(weakRefs, obj);
+		while (NULL != ref)
+		{
+			for (int i=0 ; i<4 ; i++)
+			{
+				if (0 == ref->ref[i])
+				{
+					ref->ref[i] = addr;
+					*addr = obj;
+					return obj;
+				}
+			}
+			if (ref->next == NULL)
+			{
+				break;
+			}
+			ref = ref->next;
+		}
+		if (NULL != ref)
+		{
+			ref->next = calloc(sizeof(WeakRef), 1);
+			ref->next->ref[0] = addr;
+		}
+		else
+		{
+			WeakRef newRef = {0};
+			newRef.obj = obj;
+			newRef.ref[0] = addr;
+			weak_ref_insert(weakRefs, newRef);
+		}
+	}
+	*addr = obj;
+	return obj;
+}
+
+static void zeroRefs(WeakRef *ref, BOOL shouldFree)
+{
+	if (NULL != ref->next)
+	{
+		zeroRefs(ref->next, YES);
+	}
+	for (int i=0 ; i<4 ; i++)
+	{
+		if (0 != ref->ref[i])
+		{
+			*ref->ref[i] = 0;
+		}
+	}
+	if (shouldFree)
+	{
+		free(ref);
+	}
+	else
+	{
+		memset(ref, 0, sizeof(WeakRef));
+	}
+}
+
+void objc_delete_weak_refs(id obj)
+{
+	LOCK_FOR_SCOPE(&weakRefLock);
+	WeakRef *oldRef = weak_ref_table_get(weakRefs, obj);
+	if (0 != oldRef)
+	{
+		zeroRefs(oldRef, NO);
+	}
+}
+
+id objc_loadWeakRetained(id* addr)
+{
+	LOCK_FOR_SCOPE(&weakRefLock);
+	id obj = *addr;
+	if (nil == obj) { return nil; }
+	Class cls = classForObject(obj);
+	if (&_NSConcreteMallocBlock == cls)
+	{
+		obj = block_load_weak(obj);
+	}
+	else if (objc_test_class_flag(cls, objc_class_flag_fast_arc))
+	{
+		if ((*(((intptr_t*)obj) - 1)) < 0)
+		{
+			return nil;
+		}
+	}
+	else
+	{
+		obj = _objc_weak_load(obj);
+	}
+	return objc_retain(obj);
+}
+
+id objc_loadWeak(id* object)
+{
+	return objc_autorelease(objc_loadWeakRetained(object));
+}
+
+void objc_copyWeak(id *dest, id *src)
+{
+	objc_release(objc_initWeak(dest, objc_loadWeakRetained(src)));
+}
+
+void objc_moveWeak(id *dest, id *src)
+{
+	// Don't retain or release.  While the weak ref lock is held, we know that
+	// the object can't be deallocated, so we just move the value and update
+	// the weak reference table entry to indicate the new address.
+	LOCK_FOR_SCOPE(&weakRefLock);
+	*dest = *src;
+	*src = nil;
+	WeakRef *oldRef = weak_ref_table_get(weakRefs, *dest);
+	while (NULL != oldRef)
+	{
+		for (int i=0 ; i<4 ; i++)
+		{
+			if (oldRef->ref[i] == src)
+			{
+				oldRef->ref[i] = dest;
+				return;
+			}
+		}
+	}
+}
+
+void objc_destroyWeak(id* obj)
+{
+	objc_storeWeak(obj, nil);
+}
+
+id objc_initWeak(id *object, id value)
+{
+	*object = nil;
+	return objc_storeWeak(object, value);
+}
diff --git a/third_party/libobjc/associate.m b/third_party/libobjc/associate.m
new file mode 100644
index 0000000000000000000000000000000000000000..2289dcaee2b518e095832ac29fdf4834232d8686
--- /dev/null
+++ b/third_party/libobjc/associate.m
@@ -0,0 +1,435 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "objc/runtime.h"
+#include "objc/objc-arc.h"
+#include "nsobject.h"
+#include "spinlock.h"
+#include "class.h"
+#include "dtable.h"
+#include "selector.h"
+#include "lock.h"
+#include "gc_ops.h"
+
+/**
+ * A single associative reference.  Contains the key, value, and association
+ * policy.
+ */
+struct reference
+{
+	/**
+	 * The key used for identifying this object.  Opaque pointer, should be set
+	 * to 0 when this slot is unused.
+	 */
+	void *key;
+	/**
+	 * The associated object.  Note, if the policy is assign then this may be
+	 * some other type of pointer...
+	 */
+	void *object;
+	/**
+	 * Association policy.
+	 */
+	uintptr_t policy;
+};
+
+#define REFERENCE_LIST_SIZE 10
+
+/**
+ * Linked list of references associated with an object.  We assume that there
+ * won't be very many, so we don't bother with a proper hash table, and just
+ * iterate over a list.
+ */
+struct reference_list
+{
+	/**
+	 * Next group of references.  This is only ever used if we have more than
+	 * 10 references associated with an object, which seems highly unlikely.
+	 */
+	struct reference_list *next;
+	/**
+	 * Mutex.  Only set for the first reference list in a chain.  Used for
+	 * @syncronize().
+	 */
+	mutex_t lock;
+	/**
+	 * Garbage collection type.  This stores the location of all of the
+	 * instance variables in the object that may contain pointers.
+	 */
+	void *gc_type;
+	/**
+	 * Array of references.
+	 */
+	struct reference list[REFERENCE_LIST_SIZE];
+};
+enum
+{
+	OBJC_ASSOCIATION_ATOMIC = 0x300,
+};
+
+static BOOL isAtomic(uintptr_t policy)
+{
+	return (policy & OBJC_ASSOCIATION_ATOMIC) == OBJC_ASSOCIATION_ATOMIC;
+}
+
+static struct reference* findReference(struct reference_list *list, void *key)
+{
+	if (NULL == list) { return NULL; }
+
+	for (int i=0 ; i<REFERENCE_LIST_SIZE ; i++)
+	{
+		if (list->list[i].key == key)
+		{
+			return &list->list[i];
+		}
+	}
+	return NULL;
+}
+static void cleanupReferenceList(struct reference_list *list)
+{
+	if (NULL == list) { return; }
+
+	cleanupReferenceList(list->next);
+
+	for (int i=0 ; i<REFERENCE_LIST_SIZE ; i++)
+	{
+		struct reference *r = &list->list[i];
+		if (0 != r->key)
+		{
+			r->key = 0;
+			if (OBJC_ASSOCIATION_ASSIGN != r->policy)
+			{
+				// Full barrier - ensure that we've zero'd the key before doing
+				// this!
+				__sync_synchronize();
+				objc_release(r->object);
+			}
+			r->object = 0;
+			r->policy = 0;
+		}
+	}
+}
+
+static void freeReferenceList(struct reference_list *l)
+{
+	if (NULL == l) { return; }
+	freeReferenceList(l->next);
+	gc->free(l);
+}
+
+static void setReference(struct reference_list *list,
+                         void *key,
+                         void *obj,
+                         uintptr_t policy)
+{
+	switch (policy)
+	{
+		// Ignore any unknown association policies
+		default: return;
+		case OBJC_ASSOCIATION_COPY_NONATOMIC:
+		case OBJC_ASSOCIATION_COPY:
+			obj = [(id)obj copy];
+			break;
+		case OBJC_ASSOCIATION_RETAIN_NONATOMIC:
+		case OBJC_ASSOCIATION_RETAIN:
+			obj = objc_retain(obj);
+		case OBJC_ASSOCIATION_ASSIGN:
+			break;
+	}
+	// While inserting into the list, we need to lock it temporarily.
+	volatile int *lock = lock_for_pointer(list);
+	lock_spinlock(lock);
+	struct reference *r = findReference(list, key);
+	// If there's an existing reference, then we can update it, otherwise we
+	// have to install a new one
+	if (NULL == r)
+	{
+		// Search for an unused slot
+		r = findReference(list, 0);
+		if (NULL == r)
+		{
+			struct reference_list *l = list;
+
+			while (NULL != l->next) { l = l->next; }
+
+			l->next = gc->malloc(sizeof(struct reference_list));
+			r = &l->next->list[0];
+		}
+		r->key = key;
+	}
+	unlock_spinlock(lock);
+	// Now we only need to lock if the old or new property is atomic
+	BOOL needLock = isAtomic(r->policy) || isAtomic(policy);
+	if (needLock)
+	{
+		lock = lock_for_pointer(r);
+		lock_spinlock(lock);
+	}
+	r->policy = policy;
+	id old = r->object;
+	r->object = obj;
+	if (OBJC_ASSOCIATION_ASSIGN != r->policy)
+	{
+		objc_release(old);
+	}
+	if (needLock)
+	{
+		unlock_spinlock(lock);
+	}
+}
+
+static void deallocHiddenClass(id obj, SEL _cmd);
+
+static inline Class findHiddenClass(id obj)
+{
+	Class cls = obj->isa;
+	while (Nil != cls && 
+	       !objc_test_class_flag(cls, objc_class_flag_assoc_class))
+	{
+		cls = class_getSuperclass(cls);
+	}
+	return cls;
+}
+
+static Class allocateHiddenClass(Class superclass)
+{
+	Class newClass =
+		calloc(1, sizeof(struct objc_class) + sizeof(struct reference_list));
+
+	if (Nil == newClass) { return Nil; }
+
+	// Set up the new class
+	newClass->isa = superclass->isa;
+	newClass->name = superclass->name;
+	// Uncomment this for debugging: it makes it easier to track which hidden
+	// class is which
+	// static int count;
+	//asprintf(&newClass->name, "%s%d", superclass->name, count++);
+	newClass->info = objc_class_flag_resolved | 
+		objc_class_flag_class | objc_class_flag_user_created |
+		objc_class_flag_new_abi | objc_class_flag_hidden_class |
+		objc_class_flag_assoc_class;
+	newClass->super_class = superclass;
+	newClass->dtable = uninstalled_dtable;
+	newClass->instance_size = superclass->instance_size;
+
+	newClass->sibling_class = superclass->subclass_list;
+	superclass->subclass_list = newClass;
+
+	return newClass;
+}
+
+static inline Class initHiddenClassForObject(id obj)
+{
+	Class hiddenClass = allocateHiddenClass(obj->isa); 
+	assert(!class_isMetaClass(obj->isa));
+	static SEL cxx_destruct;
+	if (NULL == cxx_destruct)
+	{
+		cxx_destruct = sel_registerName(".cxx_destruct");
+	}
+	const char *types = sizeof(void*) == 4 ? "v8@0:4" : "v16@0:8";
+	class_addMethod(hiddenClass, cxx_destruct,
+		(IMP)deallocHiddenClass, types);
+	obj->isa = hiddenClass;
+	return hiddenClass;
+}
+
+static void deallocHiddenClass(id obj, SEL _cmd)
+{
+	Class hiddenClass = findHiddenClass(obj);
+	// After calling [super dealloc], the object will no longer exist.
+	// Free the hidden
+	struct reference_list *list = object_getIndexedIvars(hiddenClass);
+	DESTROY_LOCK(&list->lock);
+	cleanupReferenceList(list);
+	freeReferenceList(list->next);
+	free_dtable(hiddenClass->dtable);
+	// Free the class
+	free(hiddenClass);
+}
+
+static struct reference_list* referenceListForObject(id object, BOOL create)
+{
+	if (class_isMetaClass(object->isa))
+	{
+		Class cls = (Class)object;
+		if ((NULL == cls->extra_data) && create)
+		{
+			volatile int *lock = lock_for_pointer(cls);
+			struct reference_list *list = gc->malloc(sizeof(struct reference_list));
+			lock_spinlock(lock);
+			if (NULL == cls->extra_data)
+			{
+				INIT_LOCK(list->lock);
+				cls->extra_data = list;
+				unlock_spinlock(lock);
+			}
+			else
+			{
+				unlock_spinlock(lock);
+				gc->free(list);
+			}
+		}
+		return cls->extra_data;
+	}
+	Class hiddenClass = findHiddenClass(object);
+	if ((NULL == hiddenClass) && create)
+	{
+		volatile int *lock = lock_for_pointer(object);
+		lock_spinlock(lock);
+		hiddenClass = findHiddenClass(object);
+		if (NULL == hiddenClass)
+		{
+			hiddenClass = initHiddenClassForObject(object);
+			struct reference_list *list = object_getIndexedIvars(hiddenClass);
+			INIT_LOCK(list->lock);
+		}
+		unlock_spinlock(lock);
+	}
+	return hiddenClass ? object_getIndexedIvars(hiddenClass) : NULL;
+}
+
+void objc_setAssociatedObject(id object,
+                              void *key,
+                              id value,
+                              objc_AssociationPolicy policy)
+{
+	if (isSmallObject(object)) { return; }
+	struct reference_list *list = referenceListForObject(object, YES);
+	setReference(list, key, value, policy);
+}
+
+id objc_getAssociatedObject(id object, void *key)
+{
+	if (isSmallObject(object)) { return nil; }
+	struct reference_list *list = referenceListForObject(object, NO);
+	if (NULL == list) { return nil; }
+	struct reference *r = findReference(list, key);
+	if (NULL != r)
+	{
+		return r->object;
+	}
+	if (class_isMetaClass(object->isa))
+	{
+		return nil;
+	}
+	Class cls = object->isa;
+	while (Nil != cls)
+	{
+		while (Nil != cls && 
+			   !objc_test_class_flag(cls, objc_class_flag_assoc_class))
+		{
+			cls = class_getSuperclass(cls);
+		}
+		if (Nil != cls)
+		{
+			struct reference_list *next_list = object_getIndexedIvars(cls);
+			if (list != next_list)
+			{
+				list = next_list;
+				struct reference *r = findReference(list, key);
+				if (NULL != r)
+				{
+					return r->object;
+				}
+			}
+			cls = class_getSuperclass(cls);
+		}
+	}
+	return nil;
+}
+
+
+void objc_removeAssociatedObjects(id object)
+{
+	if (isSmallObject(object)) { return; }
+	cleanupReferenceList(referenceListForObject(object, NO));
+}
+
+PRIVATE void *gc_typeForClass(Class cls)
+{
+	struct reference_list *list = referenceListForObject(cls, YES);
+	return list->gc_type;
+}
+PRIVATE void gc_setTypeForClass(Class cls, void *type)
+{
+	struct reference_list *list = referenceListForObject(cls, YES);
+	list->gc_type = type;
+}
+
+int objc_sync_enter(id object)
+{
+	if (isSmallObject(object)) { return 0; }
+	struct reference_list *list = referenceListForObject(object, YES);
+	LOCK(&list->lock);
+	return 0;
+}
+
+int objc_sync_exit(id object)
+{
+	if (isSmallObject(object)) { return 0; }
+	struct reference_list *list = referenceListForObject(object, NO);
+	if (NULL != list)
+	{
+		UNLOCK(&list->lock);
+		return 0;
+	}
+	return 1;
+}
+
+static Class hiddenClassForObject(id object)
+{
+	if (isSmallObject(object)) { return nil; }
+	if (class_isMetaClass(object->isa))
+	{
+		return object->isa;
+	}
+	Class hiddenClass = findHiddenClass(object);
+	if (NULL == hiddenClass)
+	{
+		volatile int *lock = lock_for_pointer(object);
+		lock_spinlock(lock);
+		hiddenClass = findHiddenClass(object);
+		if (NULL == hiddenClass)
+		{
+			hiddenClass = initHiddenClassForObject(object);
+			struct reference_list *list = object_getIndexedIvars(hiddenClass);
+			INIT_LOCK(list->lock);
+		}
+		unlock_spinlock(lock);
+	}
+	return hiddenClass;
+}
+
+BOOL object_addMethod_np(id object, SEL name, IMP imp, const char *types)
+{
+	return class_addMethod(hiddenClassForObject(object), name, imp, types);
+}
+
+IMP object_replaceMethod_np(id object, SEL name, IMP imp, const char *types)
+{
+	return class_replaceMethod(hiddenClassForObject(object), name, imp, types);
+}
+static char prototypeKey;
+
+id object_clone_np(id object)
+{
+	if (isSmallObject(object)) { return object; }
+	// Make sure that the prototype has a hidden class, so that methods added
+	// to it will appear in the clone.
+	referenceListForObject(object, YES);
+	id new = class_createInstance(object->isa, 0);
+	Class hiddenClass = initHiddenClassForObject(new);
+	struct reference_list *list = object_getIndexedIvars(hiddenClass);
+	INIT_LOCK(list->lock);
+	objc_setAssociatedObject(new, &prototypeKey, object,
+			OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+	return new;
+}
+
+id object_getPrototype_np(id object)
+{
+	return objc_getAssociatedObject(object, &prototypeKey);
+}
diff --git a/third_party/libobjc/block_to_imp.c b/third_party/libobjc/block_to_imp.c
new file mode 100644
index 0000000000000000000000000000000000000000..5b0262c69c4c229a436b5eae40a42a107813c838
--- /dev/null
+++ b/third_party/libobjc/block_to_imp.c
@@ -0,0 +1,165 @@
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include "objc/runtime.h"
+#include "objc/blocks_runtime.h"
+#include "blocks_runtime.h"
+#include "lock.h"
+#include "visibility.h"
+
+
+/* QNX needs a special header for asprintf() */
+#ifdef __QNXNTO__
+#include <nbutil.h>
+#endif
+
+#define PAGE_SIZE 4096
+
+static void *executeBuffer;
+static void *writeBuffer;
+static ptrdiff_t offset;
+static mutex_t trampoline_lock;
+static char *tmpPattern;
+
+struct wx_buffer
+{
+	void *w;
+	void *x;
+};
+
+PRIVATE void init_trampolines(void)
+{
+	INIT_LOCK(trampoline_lock);
+	char *tmp = getenv("TMPDIR");
+	if (NULL == tmp)
+	{
+		tmp = "/tmp/";
+	}
+	if (0 > asprintf(&tmpPattern, "%s/objc_trampolinesXXXXXXXXXXX", tmp))
+	{
+		abort();
+	}
+}
+
+static struct wx_buffer alloc_buffer(size_t size)
+{
+	LOCK_FOR_SCOPE(&trampoline_lock);
+	if ((0 == offset) || (offset + size >= PAGE_SIZE))
+	{
+		int fd = mkstemp(tmpPattern);
+		unlink(tmpPattern);
+		ftruncate(fd, PAGE_SIZE);
+		void *w = mmap(NULL, PAGE_SIZE, PROT_WRITE, MAP_SHARED, fd, 0);
+		executeBuffer = mmap(NULL, PAGE_SIZE, PROT_READ|PROT_EXEC, MAP_SHARED, fd, 0);
+		*((void**)w) = writeBuffer;
+		writeBuffer = w;
+		offset = sizeof(void*);
+	}
+	struct wx_buffer b = { writeBuffer + offset, executeBuffer + offset };
+	offset += size;
+	return b;
+}
+
+extern void __objc_block_trampoline;
+extern void __objc_block_trampoline_end;
+extern void __objc_block_trampoline_sret;
+extern void __objc_block_trampoline_end_sret;
+
+IMP imp_implementationWithBlock(void *block)
+{
+	struct Block_layout *b = block;
+	void *start;
+	void *end;
+
+	if ((b->flags & BLOCK_USE_SRET) == BLOCK_USE_SRET)
+	{
+		start = &__objc_block_trampoline_sret;
+		end = &__objc_block_trampoline_end_sret;
+	}
+	else
+	{
+		start = &__objc_block_trampoline;
+		end = &__objc_block_trampoline_end;
+	}
+
+	size_t trampolineSize = end - start;
+	// If we don't have a trampoline intrinsic for this architecture, return a
+	// null IMP.
+	if (0 >= trampolineSize) { return 0; }
+
+	struct wx_buffer buf = alloc_buffer(trampolineSize + 2*sizeof(void*));
+	void **out = buf.w;
+	out[0] = (void*)b->invoke;
+	out[1] = Block_copy(b);
+	memcpy(&out[2], start, trampolineSize);
+	out = buf.x;
+	return (IMP)&out[2];
+}
+
+static void* isBlockIMP(void *anIMP)
+{
+	LOCK(&trampoline_lock);
+	void *e = executeBuffer;
+	void *w = writeBuffer;
+	UNLOCK(&trampoline_lock);
+	while (e)
+	{
+		if ((anIMP > e) && (anIMP < e + PAGE_SIZE))
+		{
+			return ((char*)w) + ((char*)anIMP - (char*)e);
+		}
+		e = *(void**)e;
+		w = *(void**)w;
+	}
+	return 0;
+}
+
+void *imp_getBlock(IMP anImp)
+{
+	if (0 == isBlockIMP((void*)anImp)) { return 0; }
+	return *(((void**)anImp) - 1);
+}
+BOOL imp_removeBlock(IMP anImp)
+{
+	void *w = isBlockIMP((void*)anImp);
+	if (0 == w) { return NO; }
+	Block_release(((void**)anImp) - 1);
+	return YES;
+}
+
+PRIVATE size_t lengthOfTypeEncoding(const char *types);
+
+char *block_copyIMPTypeEncoding_np(void*block)
+{
+	char *buffer = strdup(block_getType_np(block));
+	if (NULL == buffer) { return NULL; }
+	char *replace = buffer;
+	// Skip the return type
+	replace += lengthOfTypeEncoding(replace);
+	while (isdigit(*replace)) { replace++; }
+	// The first argument type should be @? (block), and we need to transform
+	// it to @, so we have to delete the ?.  Assert here because this isn't a
+	// block encoding at all if the first argument is not a block, and since we
+	// got it from block_getType_np(), this means something is badly wrong.
+	assert('@' == *replace);
+	replace++;
+	assert('?' == *replace);
+	// Use strlen(replace) not replace+1, because we want to copy the NULL
+	// terminator as well.
+	memmove(replace, replace+1, strlen(replace));
+	// The next argument should be an object, and we want to replace it with a
+	// selector
+	while (isdigit(*replace)) { replace++; }
+	if ('@' != *replace)
+	{
+		free(buffer);
+		return NULL;
+	}
+	*replace = ':';
+	return buffer;
+}
diff --git a/third_party/libobjc/block_trampolines.S b/third_party/libobjc/block_trampolines.S
new file mode 100644
index 0000000000000000000000000000000000000000..531de55390395839ecc40562559f58147098c468
--- /dev/null
+++ b/third_party/libobjc/block_trampolines.S
@@ -0,0 +1,81 @@
+#
+# This file defines some trampolines for calling blocks.  A block function
+# looks like this:
+# 
+# retType blockFn(block*, ...)
+#
+# An IMP looks like this:
+#
+# retType imp(id, SEL,...)
+#
+# The trampoline must find the block pointer and then call the block function
+# with the correct first argument, the self pointer moved to the second real
+# argument (the first block argument) and the _cmd parameter excised
+
+.file	"block_trampolines.S"
+#if __arm__
+.syntax unified
+.globl __objc_block_trampoline_sret
+	.type	__objc_block_trampoline_sret, %function
+.globl __objc_block_trampoline_end_sret
+.globl __objc_block_trampoline
+	.type	__objc_block_trampoline, %function
+.globl __objc_block_trampoline_end
+#else
+.globl __objc_block_trampoline_sret
+	.type	__objc_block_trampoline_sret, @function
+.globl __objc_block_trampoline_end_sret
+.globl __objc_block_trampoline
+	.type	__objc_block_trampoline, @function
+.globl __objc_block_trampoline_end
+#endif
+#if __x86_64
+__objc_block_trampoline:
+	mov   -15(%rip), %rsi      # Load the block pointer into the second argument
+	xchg  %rdi, %rsi           # Swap the first and second arguments
+	jmp   *-32(%rip)           # Call the block function
+__objc_block_trampoline_end:
+__objc_block_trampoline_sret:
+	mov   -15(%rip), %rdx      # Load the block pointer into the second argument
+	xchg  %rdx, %rsi           # Swap the first and second arguments
+	jmp   *-32(%rip)           # Call the block function
+__objc_block_trampoline_end_sret:
+#elif __i386
+__objc_block_trampoline:
+	call  next_line            # Store the instruction pointer on the stack
+next_line:
+	pop   %eax                 # Load the old instruction pointer
+	mov   4(%esp), %ebx        # Load the self parameter
+	mov   %ebx, 8(%esp)        # Store self as the second argument
+	mov   -9(%eax), %ebx       # Load the block pointer to %ebx
+	mov   %ebx, 4(%esp)        # Store the block pointer in the first argument
+	jmp   *-13(%eax)           # Call the block function
+__objc_block_trampoline_end:
+__objc_block_trampoline_sret:
+	call  next_line2           # Store the instruction pointer on the stack
+next_line2:
+	pop   %eax                 # Load the old instruction pointer
+	mov   8(%esp), %ebx        # Load the self parameter
+	mov   %ebx, 12(%esp)       # Store self as the second argument
+	mov   -9(%eax), %ebx       # Load the block pointer to %ebx
+	mov   %ebx, 8(%esp)        # Store the block pointer in the first argument
+	jmp   *-13(%eax)           # Call the block function
+__objc_block_trampoline_end_sret:
+#elif __arm__
+__objc_block_trampoline:
+	mov r1, r0                 // Move self over _cmd
+	ldr r0, [pc, #-16]         // Load the block pointer over self
+	ldr pc, [pc, #-24]         // Jump to the block function
+__objc_block_trampoline_end:
+__objc_block_trampoline_sret:
+	mov r2, r1                 // Move self over _cmd
+	ldr r1, [pc, #-16]         // Load the block pointer over self
+	ldr pc, [pc, #-24]         // Jump to the block function
+__objc_block_trampoline_end_sret:
+#else
+#warning imp_implementationWithBlock() not implemented for your architecture
+__objc_block_trampoline:
+__objc_block_trampoline_end:
+__objc_block_trampoline_sret:
+__objc_block_trampoline_end_sret:
+#endif
diff --git a/third_party/libobjc/blocks_runtime.h b/third_party/libobjc/blocks_runtime.h
new file mode 100644
index 0000000000000000000000000000000000000000..f69490ae956962d1c67fe371c1db18d74a451ce6
--- /dev/null
+++ b/third_party/libobjc/blocks_runtime.h
@@ -0,0 +1,125 @@
+/**
+ * Block descriptor flags.
+ */
+enum block_flags
+{
+	/**
+	 * The block descriptor contains copy and dispose helpers.
+	 */
+	BLOCK_HAS_COPY_DISPOSE = (1 << 25),
+	/**
+	 * The helpers have C++ code.
+	 */
+	BLOCK_HAS_CTOR         = (1 << 26),
+	/**
+	 * Block is stored in global memory and does not need to be copied.
+	 */
+	BLOCK_IS_GLOBAL        = (1 << 28),
+	/**
+	 * Block function uses a calling convention that returns a structure via a
+	 * pointer passed in by the caller.
+	 */
+	BLOCK_USE_SRET         = (1 << 29),
+	/**
+	 * Block has an Objective-C type encoding.
+	 */
+	BLOCK_HAS_SIGNATURE    = (1 << 30),
+	/**
+	 * Mask for the reference count in byref structure's flags field.  The low
+	 * 3 bytes are reserved for the reference count, the top byte for the
+	 * flags.
+	 */
+	BLOCK_REFCOUNT_MASK    = 0x00ffffff
+};
+
+/**
+ * Flags used in the final argument to _Block_object_assign() and
+ * _Block_object_dispose().  These indicate the type of copy or dispose to
+ * perform.
+ */
+enum
+{
+	/**
+	 * The value is of some id-like type, and should be copied as an
+	 * Objective-C object: i.e. by sending -retain or via the GC assign
+	 * functions in GC mode (not yet supported).
+	 */
+	BLOCK_FIELD_IS_OBJECT   =  3,
+	/**
+	 * The field is a block.  This must be copied by the block copy functions.
+	 */
+	BLOCK_FIELD_IS_BLOCK	=  7,
+	/**
+	 * The field is an indirect reference to a variable declared with the
+	 * __block storage qualifier.
+	 */
+	BLOCK_FIELD_IS_BYREF	=  8,  // the on stack structure holding the __block variable
+
+	BLOCK_FIELD_IS_WEAK	 = 16,  // declared __weak
+
+	BLOCK_BYREF_CALLER	  = 128, // called from byref copy/dispose helpers
+};
+#define IS_SET(x, y) ((x & y) == y)
+
+/*
+ * Include the block_descriptor_copydispose and block_literal definitions that
+ * are also made public under different names for use in libdispatch.
+ */
+#include "objc/blocks_private.h"
+
+/**
+ * Block descriptor that does not contain copy and dispose helper functions.
+ */
+struct Block_descriptor_basic
+{
+	/**
+	 * Reserved for future use, currently always 0.
+	 */
+	unsigned long int reserved;
+	/** Size of the block. */
+	unsigned long int size;
+	/**
+	 * Objective-C type encoding of the block.
+	 */
+	const char *encoding;
+};
+
+
+/**
+ * Structure used for on-stack variables that are referenced by blocks.
+ */
+struct block_byref_obj
+{
+	/**
+	 * Class pointer.  Currently unused and always NULL.  Could be used in the
+	 * future to support introspection.
+	 */
+	void *isa;
+	/**
+	 * The pointer to the structure that contains the real version of the data.
+	 * All accesses go via this pointer.  If an on-stack byref structure is
+	 * copied to the heap, then its forwarding pointer should point to the heap
+	 * version.  Otherwise it should point to itself.
+	 */
+	struct block_byref_obj *forwarding;
+	/**
+	 * Flags and reference count.
+	 */
+	int flags;   //refcount;
+	/**
+	 * Size of this structure.
+	 */
+	int size;
+	/**
+	 * Copy function.
+	 */
+	void (*byref_keep)(struct block_byref_obj *dst, const struct block_byref_obj *src);
+	/**
+	 * Dispose function.
+	 */
+	void (*byref_dispose)(struct block_byref_obj *);
+	/**
+	 * __block-qualified variables are copied here.
+	 */
+};
+
diff --git a/third_party/libobjc/blocks_runtime.m b/third_party/libobjc/blocks_runtime.m
new file mode 100644
index 0000000000000000000000000000000000000000..0ba796129d8a822c92c665805799367c4d3dbba4
--- /dev/null
+++ b/third_party/libobjc/blocks_runtime.m
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2009 Remy Demarest
+ * Portions Copyright (c) 2009 David Chisnall
+ *
+ *  Permission is hereby granted, free of charge, to any person
+ *  obtaining a copy of this software and associated documentation
+ *  files (the "Software"), to deal in the Software without
+ *  restriction, including without limitation the rights to use,
+ *  copy, modify, merge, publish, distribute, sublicense, and/or sell
+ *  copies of the Software, and to permit persons to whom the
+ *  Software is furnished to do so, subject to the following
+ *  conditions:
+ *
+ *  The above copyright notice and this permission notice shall be
+ *  included in all copies or substantial portions of the Software.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ *  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ *  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ *  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ *  OTHER DEALINGS IN THE SOFTWARE.
+ */
+#import "objc/blocks_runtime.h"
+#import "objc/runtime.h"
+#import "objc/objc-arc.h"
+#include "blocks_runtime.h"
+#include "gc_ops.h"
+#include "visibility.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+
+
+static void *_HeapBlockByRef = (void*)1;
+
+
+/**
+ * Returns the Objective-C type encoding for the block.
+ */
+const char *block_getType_np(void *b)
+{
+	struct Block_layout *block = b;
+	if ((NULL == block) || !(block->flags & BLOCK_HAS_SIGNATURE))
+	{
+		return NULL;
+	}
+	if (!(block->flags & BLOCK_HAS_COPY_DISPOSE))
+	{
+		return ((struct Block_descriptor_basic*)block->descriptor)->encoding;
+	}
+	return block->descriptor->encoding;
+}
+
+static int increment24(int *ref)
+{
+	int old = *ref;
+	int val = old & BLOCK_REFCOUNT_MASK;
+	// FIXME: We should gracefully handle refcount overflow, but for now we
+	// just give up
+	assert(val < BLOCK_REFCOUNT_MASK);
+	if (!__sync_bool_compare_and_swap(ref, old, old+1))
+	{
+		return increment24(ref);
+	}
+	return val + 1;
+}
+
+static int decrement24(int *ref)
+{
+	int old = *ref;
+	int val = old & BLOCK_REFCOUNT_MASK;
+	// FIXME: We should gracefully handle refcount overflow, but for now we
+	// just give up
+	assert(val > 0);
+	if (!__sync_bool_compare_and_swap(ref, old, old-1))
+	{
+		return decrement24(ref);
+	}
+	return val - 1;
+}
+
+// This is a really ugly hack that works around a buggy register allocator in
+// GCC.  Compiling nontrivial code using __sync_bool_compare_and_swap() with
+// GCC (4.2.1, at least), causes the register allocator to run out of registers
+// and fall over and die.  We work around this by wrapping this CAS in a
+// function, which means the register allocator can trivially handle it.  Do
+// not remove the noinline attribute - without it, gcc will inline it early on
+// and then crash later.
+#ifndef __clang__
+__attribute__((noinline))
+static int cas(void *ptr, void *old, void *new)
+{
+	return __sync_bool_compare_and_swap((void**)ptr, old, new);
+}
+#define __sync_bool_compare_and_swap cas
+#endif
+
+/* Certain field types require runtime assistance when being copied to the
+ * heap.  The following function is used to copy fields of types: blocks,
+ * pointers to byref structures, and objects (including
+ * __attribute__((NSObject)) pointers.  BLOCK_FIELD_IS_WEAK is orthogonal to
+ * the other choices which are mutually exclusive.  Only in a Block copy helper
+ * will one see BLOCK_FIELD_IS_BYREF.
+ */
+void _Block_object_assign(void *destAddr, const void *object, const int flags)
+{
+	//printf("Copying %x to %x with flags %x\n", object, destAddr, flags);
+	// FIXME: Needs to be implemented
+	//if(flags & BLOCK_FIELD_IS_WEAK)
+	{
+	}
+	//else
+	{
+		if (IS_SET(flags, BLOCK_FIELD_IS_BYREF))
+		{
+			struct block_byref_obj *src = (struct block_byref_obj *)object;
+			struct block_byref_obj **dst = destAddr;
+			src = src->forwarding;
+
+			if ((src->flags & BLOCK_REFCOUNT_MASK) == 0)
+			{
+				*dst = gc->malloc(src->size);
+				memcpy(*dst, src, src->size);
+				(*dst)->isa = _HeapBlockByRef;
+				// Refcount must be two; one for the copy and one for the
+				// on-stack version that will point to it.
+				(*dst)->flags += 2;
+				if (IS_SET(src->flags, BLOCK_HAS_COPY_DISPOSE))
+				{
+					src->byref_keep(*dst, src);
+				}
+				(*dst)->forwarding = *dst;
+				// Concurrency.  If we try copying the same byref structure
+				// from two threads simultaneously, we could end up with two
+				// versions on the heap that are unaware of each other.  That
+				// would be bad.  So we first set up the copy, then try to do
+				// an atomic compare-and-exchange to point the old version at
+				// it.  If the forwarding pointer in src has changed, then we
+				// recover - clean up and then return the structure that the
+				// other thread created.
+				if (!__sync_bool_compare_and_swap(&src->forwarding, src, *dst))
+				{
+					if((size_t)src->size >= sizeof(struct block_byref_obj))
+					{
+						src->byref_dispose(*dst);
+					}
+					gc->free(*dst);
+					*dst = src->forwarding;
+				}
+			}
+			else
+			{
+				*dst = (struct block_byref_obj*)src;
+				increment24(&(*dst)->flags);
+			}
+		}
+		else if (IS_SET(flags, BLOCK_FIELD_IS_BLOCK))
+		{
+			struct Block_layout *src = (struct Block_layout*)object;
+			struct Block_layout **dst = destAddr;
+
+			*dst = Block_copy(src);
+		}
+		else if (IS_SET(flags, BLOCK_FIELD_IS_OBJECT) &&
+		         !IS_SET(flags, BLOCK_BYREF_CALLER))
+		{
+			id src = (id)object;
+			void **dst = destAddr;
+			*dst = src;
+			if (!isGCEnabled)
+			{
+				*dst = objc_retain(src);
+			}
+		}
+	}
+}
+
+/* Similarly a compiler generated dispose helper needs to call back for each
+ * field of the byref data structure.  (Currently the implementation only packs
+ * one field into the byref structure but in principle there could be more).
+ * The same flags used in the copy helper should be used for each call
+ * generated to this function:
+ */
+void _Block_object_dispose(const void *object, const int flags)
+{
+	// FIXME: Needs to be implemented
+	//if(flags & BLOCK_FIELD_IS_WEAK)
+	{
+	}
+	//else
+	{
+		if (IS_SET(flags, BLOCK_FIELD_IS_BYREF))
+		{
+			struct block_byref_obj *src =
+				(struct block_byref_obj*)object;
+			src = src->forwarding;
+			if (src->isa == _HeapBlockByRef)
+			{
+				int refcount = (src->flags & BLOCK_REFCOUNT_MASK) == 0 ? 0 : decrement24(&src->flags);
+				if (refcount == 0)
+				{
+					if(IS_SET(src->flags, BLOCK_HAS_COPY_DISPOSE) && (0 != src->byref_dispose))
+					{
+						src->byref_dispose(src);
+					}
+					gc->free(src);
+				}
+			}
+		}
+		else if (IS_SET(flags, BLOCK_FIELD_IS_BLOCK))
+		{
+			struct Block_layout *src = (struct Block_layout*)object;
+			Block_release(src);
+		}
+		else if (IS_SET(flags, BLOCK_FIELD_IS_OBJECT) &&
+		         !IS_SET(flags, BLOCK_BYREF_CALLER))
+		{
+			id src = (id)object;
+			if (!isGCEnabled)
+			{
+				objc_release(src);
+			}
+		}
+	}
+}
+
+
+// Copy a block to the heap if it's still on the stack or increments its retain count.
+void *_Block_copy(void *src)
+{
+	if (NULL == src) { return NULL; }
+	struct Block_layout *self = src;
+	struct Block_layout *ret = self;
+
+	extern void _NSConcreteStackBlock;
+	extern void _NSConcreteMallocBlock;
+
+	// If the block is Global, there's no need to copy it on the heap.
+	if(self->isa == &_NSConcreteStackBlock)
+	{
+		ret = gc->malloc(self->descriptor->size);
+		memcpy(ret, self, self->descriptor->size);
+		ret->isa = &_NSConcreteMallocBlock;
+		if(self->flags & BLOCK_HAS_COPY_DISPOSE)
+		{
+			self->descriptor->copy_helper(ret, self);
+		}
+		// We don't need any atomic operations here, because on-stack blocks
+		// can not be aliased across threads (unless you've done something
+		// badly wrong).
+		ret->reserved = 1;
+	}
+	else if (self->isa == &_NSConcreteMallocBlock)
+	{
+		// We need an atomic increment for malloc'd blocks, because they may be
+		// shared.
+		__sync_fetch_and_add(&ret->reserved, 1);
+	}
+	return ret;
+}
+
+// Release a block and frees the memory when the retain count hits zero.
+void _Block_release(void *src)
+{
+	if (NULL == src) { return; }
+	struct Block_layout *self = src;
+
+	extern void _NSConcreteStackBlock;
+	extern void _NSConcreteMallocBlock;
+
+	if (&_NSConcreteStackBlock == self->isa)
+	{
+		fprintf(stderr, "Block_release called upon a stack Block: %p, ignored\n", self);
+	}
+	else if (&_NSConcreteMallocBlock == self->isa)
+	{
+		if (__sync_sub_and_fetch(&self->reserved, 1) == 0)
+		{
+			if(self->flags & BLOCK_HAS_COPY_DISPOSE)
+				self->descriptor->dispose_helper(self);
+			objc_delete_weak_refs((id)self);
+			gc->free(self);
+		}
+	}
+}
+
+PRIVATE void* block_load_weak(void *block)
+{
+	struct Block_layout *self = block;
+	return (self->reserved) > 0 ? block : 0;
+}
diff --git a/third_party/libobjc/buffer.h b/third_party/libobjc/buffer.h
new file mode 100644
index 0000000000000000000000000000000000000000..4658ee127f1b362a440211bc2507571200edc09a
--- /dev/null
+++ b/third_party/libobjc/buffer.h
@@ -0,0 +1,62 @@
+/**
+ * buffer.h defines a simple dynamic array that is used to store temporary
+ * values for later processing.  Define BUFFER_TYPE before including this file.
+ */
+
+#include <stdlib.h>
+
+#define BUFFER_SIZE 128
+static BUFFER_TYPE *buffered_object_buffer[BUFFER_SIZE];
+static BUFFER_TYPE **buffered_object_overflow;
+static int buffered_objects;
+static int buffered_object_overflow_space;
+
+static void set_buffered_object_at_index(BUFFER_TYPE *cat, unsigned int i)
+{
+	if (i < BUFFER_SIZE)
+	{
+		buffered_object_buffer[i] = cat;
+	}
+	else
+	{
+		i -= BUFFER_SIZE;
+		if (NULL == buffered_object_overflow)
+		{
+			buffered_object_overflow =
+				calloc(BUFFER_SIZE, sizeof(BUFFER_TYPE*));
+			buffered_object_overflow_space = BUFFER_SIZE;
+		}
+		while (i >= buffered_object_overflow_space)
+		{
+			buffered_object_overflow_space <<= 1;
+			buffered_object_overflow = realloc(buffered_object_overflow,
+					buffered_object_overflow_space * sizeof(BUFFER_TYPE*));
+		}
+		buffered_object_overflow[i] = cat;
+	}
+}
+
+static BUFFER_TYPE *buffered_object_at_index(unsigned int i)
+{
+	if (i<BUFFER_SIZE)
+	{
+		return buffered_object_buffer[i];
+	}
+	return buffered_object_overflow[i-BUFFER_SIZE];
+}
+
+static void compact_buffer(void)
+{
+	// Move up all of the non-NULL pointers
+	unsigned size = buffered_objects;
+	unsigned insert = 0;
+	for (unsigned i=0 ; i<size ; i++)
+	{
+		BUFFER_TYPE *c = buffered_object_at_index(i);
+		if (c != NULL)
+		{
+			set_buffered_object_at_index(c, insert++);
+		}
+	}
+	buffered_objects = insert;
+}
diff --git a/third_party/libobjc/build_opts.sh b/third_party/libobjc/build_opts.sh
new file mode 100644
index 0000000000000000000000000000000000000000..2aea6c10667ac0d104c769f27171f56d19d52e93
--- /dev/null
+++ b/third_party/libobjc/build_opts.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+LLVM_PATH=`llvm-config --src-root`
+LIBOBJC_PATH=`pwd`
+if [ x$LLVM_PATH != x ] ; then
+	if [ -d $LLVM_PATH ] ; then
+		cd $LLVM_PATH
+		cd lib/Transforms
+		if [ ! -d GNURuntime ] ; then
+			mkdir GNURuntime
+		fi
+		cd GNURuntime
+		for I in `ls $LIBOBJC_PATH/opts/` ; do
+			if [ ! $I -nt $LIBOBJC_PATH/opts/$I ] ; then
+				cp $LIBOBJC_PATH/opts/$I .
+			fi
+		done
+		$1 $2
+		cd ..
+	fi
+fi
diff --git a/third_party/libobjc/caps.c b/third_party/libobjc/caps.c
new file mode 100644
index 0000000000000000000000000000000000000000..5010ff1b1a888db8068deeedc986bbd3ed08401f
--- /dev/null
+++ b/third_party/libobjc/caps.c
@@ -0,0 +1,39 @@
+#include "objc/capabilities.h"
+#include <stdint.h>
+
+/**
+ * Bitmask of all of the capabilities compiled into this version of the
+ * runtime.
+ */
+static const int32_t caps =
+	(1<<OBJC_CAP_EXCEPTIONS) |
+	(1<<OBJC_CAP_SYNCRONIZE) |
+	(1<<OBJC_CAP_PROPERTIES) |
+	(1<<OBJC_CAP_PROPERTY_INTROSPECTION) |
+	(1<<OBJC_CAP_OPTIONAL_PROTOCOLS) |
+	(1<<OBJC_CAP_NONFRAGILE_IVARS) |
+	(1<<OBJC_DEVELOPER_MODE) |
+	(1<<OBJC_CAP_REGISTERED_COMPATIBILITY_ALIASES) |
+	(1<<OBJC_CAP_ARC) |
+	(1<<OBJC_CAP_ASSOCIATED_REFERENCES) |
+	(1<<OBJC_CAP_PROTOTYPES) |
+#ifndef NO_OBJCXX
+	(1<<OBJC_UNIFIED_EXCEPTION_MODEL) |
+#endif
+#ifdef TYPE_DEPENDENT_DISPATCH
+	(1<<OBJC_CAP_TYPE_DEPENDENT_DISPATCH) |
+#endif
+#ifdef __OBJC_LOW_MEMORY__
+	(1<<OBJC_CAP_LOW_MEMORY) |
+#endif
+#ifdef ENABLE_GC
+	(1<<OBJC_CAP_GARBAGE_COLLECTION) |
+#endif
+	0;
+
+int objc_test_capability(int x)
+{
+	if (x >= 32) { return 0; }
+	if (caps & (1<<x)) { return 1; }
+	return 0;
+}
diff --git a/third_party/libobjc/category.h b/third_party/libobjc/category.h
new file mode 100644
index 0000000000000000000000000000000000000000..44eb892e6daa750941eab447e4793887a9454839
--- /dev/null
+++ b/third_party/libobjc/category.h
@@ -0,0 +1,35 @@
+
+/**
+ * The structure used to represent a category.
+ *
+ * This provides a set of new definitions that are used to replace those
+ * contained within a class.
+ *
+ * Note: Objective-C 2 allows properties to be added to classes.  The current
+ * ABI does not provide a field for adding properties in categories.  This is
+ * likely to be added with ABI version 10.  Until then, the methods created by
+ * a declared property will work, but introspection on the property will not.
+ */
+struct objc_category 
+{
+	/** 
+	 * The name of this category.
+	 */
+	const char                *name;
+	/**
+	 * The name of the class to which this category should be applied.
+	 */
+	const char                *class_name;
+	/**
+	 * The list of instance methods to add to the class.
+	 */
+	struct objc_method_list   *instance_methods;
+	/**
+	 * The list of class methods to add to the class.
+	 */
+	struct objc_method_list   *class_methods;
+	/**
+	 * The list of protocols adopted by this category.
+	 */
+	struct objc_protocol_list *protocols;
+};
diff --git a/third_party/libobjc/category_loader.c b/third_party/libobjc/category_loader.c
new file mode 100644
index 0000000000000000000000000000000000000000..cb0e020adace2bfe41c369085fa480e403a16c89
--- /dev/null
+++ b/third_party/libobjc/category_loader.c
@@ -0,0 +1,91 @@
+#include <stdio.h>
+#include "objc/runtime.h"
+#include "visibility.h"
+#include "loader.h"
+#include "dtable.h"
+
+#define BUFFER_TYPE struct objc_category
+#include "buffer.h"
+
+void objc_send_load_message(Class class);
+
+static void register_methods(struct objc_class *cls, struct objc_method_list *l)
+{
+	if (NULL == l) { return; }
+
+	// Replace the method names with selectors.
+	objc_register_selectors_from_list(l);
+	// Add the method list at the head of the list of lists.
+	l->next = cls->methods;
+	cls->methods = l;
+	// Update the dtable to catch the new methods, if the dtable has been
+	// created (don't bother creating dtables for classes when categories are
+	// loaded if the class hasn't received any messages yet.
+	if (classHasDtable(cls))
+	{
+		add_method_list_to_class(cls, l);
+	}
+}
+
+static void load_category(struct objc_category *cat, struct objc_class *class)
+{
+	register_methods(class, cat->instance_methods);
+	register_methods(class->isa, cat->class_methods);
+	//fprintf(stderr, "Loading %s (%s)\n", cat->class_name, cat->name);
+
+	if (cat->protocols)
+	{
+		objc_init_protocols(cat->protocols);
+		cat->protocols->next = class->protocols;
+		class->protocols = cat->protocols;
+	}
+}
+
+static BOOL try_load_category(struct objc_category *cat)
+{
+	Class class = (Class)objc_getClass(cat->class_name);
+	//fprintf(stderr, "Trying to load %s (%s)\n", cat->class_name, cat->name);
+	if (Nil != class)
+	{
+		load_category(cat, class);
+		return YES;
+	}
+	//fprintf(stderr, "waiting to load %s (%s)\n", cat->class_name, cat->name);
+	return NO;
+}
+
+/**
+ * Attaches a category to its class, if the class is already loaded.  Buffers
+ * it for future resolution if not.
+ */
+PRIVATE void objc_try_load_category(struct objc_category *cat)
+{
+	if (!try_load_category(cat))
+	{
+		set_buffered_object_at_index(cat, buffered_objects++);
+	}
+}
+
+PRIVATE void objc_load_buffered_categories(void)
+{
+	BOOL shouldReshuffle = NO;
+
+	for (unsigned i=0 ; i<buffered_objects ; i++)
+	{
+		struct objc_category *c = buffered_object_at_index(i);
+		if (NULL != c)
+		{
+			if (try_load_category(c))
+			{
+				set_buffered_object_at_index(NULL, i);
+				shouldReshuffle = YES;
+			}
+		}
+	}
+
+	if (shouldReshuffle)
+	{
+		compact_buffer();
+	}
+}
+
diff --git a/third_party/libobjc/class.h b/third_party/libobjc/class.h
new file mode 100644
index 0000000000000000000000000000000000000000..e37ab8b3c7c8018746e536290df138aabfafd281
--- /dev/null
+++ b/third_party/libobjc/class.h
@@ -0,0 +1,288 @@
+#ifndef __OBJC_CLASS_H_INCLUDED
+#define __OBJC_CLASS_H_INCLUDED
+#include "visibility.h"
+
+/**
+ * Overflow bitfield.  Used for bitfields that are more than 63 bits.
+ */
+struct objc_bitfield
+{
+	/**
+	 * The number of elements in the values array.
+	 */
+	int32_t  length;
+	/**
+	 * An array of values.  Each 32 bits is stored in the native endian for the
+	 * platform.
+	 */
+	int32_t values[0];
+};
+
+struct objc_class
+{
+	/**
+	 * Pointer to the metaclass for this class.  The metaclass defines the
+	 * methods use when a message is sent to the class, rather than an
+	 * instance.
+	 */
+	struct objc_class         *isa;
+	/**
+	 * Pointer to the superclass.  The compiler will set this to the name of
+	 * the superclass, the runtime will initialize it to point to the real
+	 * class.
+	 */
+	struct objc_class         *super_class;
+	/**
+	 * The name of this class.  Set to the same value for both the class and
+	 * its associated metaclass.
+	 */
+	const char                *name;
+	/**
+	 * The version of this class.  This is not used by the language, but may be
+	 * set explicitly at class load time.
+	 */
+	long                       version;
+	/**
+	 * A bitfield containing various flags.  See the objc_class_flags
+	 * enumerated type for possible values.  
+	 */
+	unsigned long              info;
+	/**
+	 * The size of this class.  For classes using the non-fragile ABI, the
+	 * compiler will set this to a negative value The absolute value will be
+	 * the size of the instance variables defined on just this class.  When
+	 * using the fragile ABI, the instance size is the size of instances of
+	 * this class, including any instance variables defined on superclasses.
+	 *
+	 * In both cases, this will be set to the size of an instance of the class
+	 * after the class is registered with the runtime.
+	 */
+	long                       instance_size;
+	/**
+	 * Metadata describing the instance variables in this class.
+	 */
+	struct objc_ivar_list     *ivars;
+	/**
+	 * Metadata for for defining the mappings from selectors to IMPs.  Linked
+	 * list of method list structures, one per class and one per category.
+	 */
+	struct objc_method_list   *methods;
+	/**
+	 * The dispatch table for this class.  Intialized and maintained by the
+	 * runtime.
+	 */
+	void                      *dtable;
+	/**
+	 * A pointer to the first subclass for this class.  Filled in by the
+	 * runtime.
+	 */
+	struct objc_class         *subclass_list;
+	/**
+	 * A pointer to the next sibling class to this.  You may find all
+	 * subclasses of a given class by following the subclass_list pointer and
+	 * then subsequently following the sibling_class pointers in the
+	 * subclasses.
+	 */
+	struct objc_class         *sibling_class;
+
+	/**
+	 * Metadata describing the protocols adopted by this class.  Not used by
+	 * the runtime.
+	 */
+	struct objc_protocol_list *protocols;
+	/**
+	 * Linked list of extra data attached to this class.
+	 */
+	struct reference_list     *extra_data;
+	/**
+	* New ABI.  The following fields are only available with classes compiled to
+	* support the new ABI.  You may test whether any given class supports this
+	* ABI by using the CLS_ISNEW_ABI() macro.
+	*/
+
+	/**
+	* The version of the ABI used for this class.  Zero indicates the ABI first
+	* implemented by clang 1.0.  One indicates the presence of bitmaps
+	* indicating the offsets of strong, weak, and unretained ivars.
+	*/
+	long                       abi_version;
+
+	/** 
+	* Array of pointers to variables where the runtime will store the ivar
+	* offset.  These may be used for faster access to non-fragile ivars if all
+	* of the code is compiled for the new ABI.  Each of these pointers should
+	* have the mangled name __objc_ivar_offset_value_{class name}.{ivar name}
+	*
+	* When using the compatible non-fragile ABI, this faster form should only be
+	* used for classes declared in the same compilation unit.
+	*
+	* The compiler should also emit symbols of the form 
+	* __objc_ivar_offset_{class name}.{ivar name} which are pointers to the
+	* offset values.  These should be emitted as weak symbols in every module
+	* where they are used.  The legacy-compatible ABI uses these with a double
+	* layer of indirection.
+	*/
+	int                      **ivar_offsets;
+	/**
+	* List of declared properties on this class (NULL if none).  This contains
+	* the accessor methods for each property.
+	*/
+	struct objc_property_list *properties;
+
+	/**
+	 * GC / ARC ABI: Fields below this point only exist if abi_version is >= 1.
+	 */
+
+	/**
+	 * The location of all strong pointer ivars declared by this class.  
+	 *
+	 * If the low bit of this field is 0, then this is a pointer to an
+	 * objc_bitfield structure.  If the low bit is 1, then the remaining 63
+	 * bits are set, from low to high, for each ivar in the object that is a
+	 * strong pointer.
+	 */
+	intptr_t                   strong_pointers;
+	/**
+	 * The location of all zeroing weak pointer ivars declared by this class.
+	 * The format of this field is the same as the format of the
+	 * strong_pointers field.
+	 */
+	intptr_t                   weak_pointers;
+};
+
+/**
+ * Structure representing the old ABI class structure.  This is only ever
+ * required so that we can take its size - struct objc_class begins with the
+ * same fields, and you can test the new abi flag to tell whether it is safe to
+ * access the subsequent fields.
+ */
+struct legacy_abi_objc_class
+{
+	struct objc_class         *isa;
+	struct objc_class         *super_class;
+	const char                *name;
+	long                       version;
+	unsigned long              info;
+	long                       instance_size;
+	struct objc_ivar_list     *ivars;
+	struct objc_method_list   *methods;
+	void                      *dtable;
+	struct objc_class         *subclass_list;
+	struct objc_class         *sibling_class;
+	struct objc_protocol_list *protocols;
+	void                      *gc_object_type;
+};
+
+
+/**
+ * An enumerated type describing all of the valid flags that may be used in the
+ * info field of a class.
+ */
+enum objc_class_flags
+{
+	/** This class structure represents a class. */
+	objc_class_flag_class = (1<<0),
+	/** This class structure represents a metaclass. */
+	objc_class_flag_meta = (1<<1),
+	/**
+	 * This class has been sent a +initalize message.  This message is sent
+	 * exactly once to every class that is sent a message by the runtime, just
+	 * before the first other message is sent.
+	 */
+	objc_class_flag_initialized = (1<<2),
+	/** 
+	 * The class has been initialized by the runtime.  Its super_class pointer
+	 * should now point to a class, rather than a C string containing the class
+	 * name, and its subclass and sibling class links will have been assigned,
+	 * if applicable.
+	 */
+	objc_class_flag_resolved = (1<<3),
+	/** 
+	 * The class uses the new, Objective-C 2, runtime ABI.  This ABI defines an
+	 * ABI version field inside the class, and so will be used for all
+	 * subsequent versions that retain some degree of compatibility.
+	 */
+	objc_class_flag_new_abi = (1<<4),
+	/**
+	 * This class was created at run time and may be freed.
+	 */
+	objc_class_flag_user_created = (1<<5),
+	/** 
+	 * Instances of this class are provide ARC-safe retain / release /
+	 * autorelease implementations.
+	 */
+	objc_class_flag_fast_arc = (1<<6),
+	/**
+	 * This class is a hidden class (should not be registered in the class
+	 * table nor returned from object_getClass()).
+	 */
+	objc_class_flag_hidden_class = (1<<7),
+	/**
+	 * This class is a hidden class used to store associated values.
+	 */
+	objc_class_flag_assoc_class = (1<<8)
+};
+
+/**
+ * Sets the specific class flag.  Note: This is not atomic.
+ */
+static inline void objc_set_class_flag(struct objc_class *aClass,
+                                       enum objc_class_flags flag)
+{
+	aClass->info |= (unsigned long)flag;
+}
+/**
+ * Unsets the specific class flag.  Note: This is not atomic.
+ */
+static inline void objc_clear_class_flag(struct objc_class *aClass,
+                                         enum objc_class_flags flag)
+{
+	aClass->info &= ~(unsigned long)flag;
+}
+/**
+ * Checks whether a specific class flag is set.
+ */
+static inline BOOL objc_test_class_flag(struct objc_class *aClass,
+                                        enum objc_class_flags flag)
+{
+	return (aClass->info & (unsigned long)flag) == (unsigned long)flag;
+}
+
+/**
+ * Adds a class to the class table.
+ */
+void class_table_insert(Class class);
+
+/**
+ * Array of classes used for small objects.  Small objects are embedded in
+ * their pointer.  In 32-bit mode, we have one small object class (typically
+ * used for storing 31-bit signed integers.  In 64-bit mode then we can have 7,
+ * because classes are guaranteed to be word aligned. 
+ */
+extern Class SmallObjectClasses[7];
+
+static BOOL isSmallObject(id obj)
+{
+	uintptr_t addr = ((uintptr_t)obj);
+	return (addr & OBJC_SMALL_OBJECT_MASK) != 0;
+}
+
+__attribute__((always_inline))
+static inline Class classForObject(id obj)
+{
+	if (UNLIKELY(isSmallObject(obj)))
+	{
+		if (sizeof(Class) == 4)
+		{
+			return SmallObjectClasses[0];
+		}
+		else
+		{
+			uintptr_t addr = ((uintptr_t)obj);
+			return SmallObjectClasses[(addr & OBJC_SMALL_OBJECT_MASK)];
+		}
+	}
+	return obj->isa;
+}
+
+#endif //__OBJC_CLASS_H_INCLUDED
diff --git a/third_party/libobjc/class_table.c b/third_party/libobjc/class_table.c
new file mode 100644
index 0000000000000000000000000000000000000000..8feb1f4890f97db32e303ef314133e27e8c3533b
--- /dev/null
+++ b/third_party/libobjc/class_table.c
@@ -0,0 +1,553 @@
+#include "objc/runtime.h"
+#include "objc/hooks.h"
+#include "objc/developer.h"
+#include "alias.h"
+#include "class.h"
+#include "method_list.h"
+#include "selector.h"
+#include "lock.h"
+#include "ivar.h"
+#include "dtable.h"
+#include "visibility.h"
+#include <stdlib.h>
+#include <assert.h>
+
+void objc_register_selectors_from_class(Class class);
+void objc_init_protocols(struct objc_protocol_list *protos);
+void objc_compute_ivar_offsets(Class class);
+
+////////////////////////////////////////////////////////////////////////////////
+// +load method hash table
+////////////////////////////////////////////////////////////////////////////////
+static int imp_compare(const void *i1, void *i2)
+{
+	return i1 == i2;
+}
+static int32_t imp_hash(const void *imp)
+{
+	return (int32_t)(((uintptr_t)imp) >> 4);
+}
+#define MAP_TABLE_NAME load_messages
+#define MAP_TABLE_COMPARE_FUNCTION imp_compare
+#define MAP_TABLE_HASH_KEY imp_hash
+#define MAP_TABLE_HASH_VALUE imp_hash
+#include "hash_table.h"
+
+static load_messages_table *load_table;
+
+SEL loadSel;
+
+PRIVATE void objc_init_load_messages_table(void)
+{
+	load_messages_initialize(&load_table, 4096);
+	loadSel = sel_registerName("load");
+}
+
+PRIVATE void objc_send_load_message(Class class)
+{
+	Class meta = class->isa;
+	for (struct objc_method_list *l=meta->methods ; NULL!=l ; l=l->next)
+	{
+		for (int i=0 ; i<l->count ; i++)
+		{
+			Method m = &l->methods[i];
+			if (sel_isEqual(m->selector, loadSel))
+			{
+				if (load_messages_table_get(load_table, m->imp) == 0)
+				{
+					m->imp((id)class, loadSel);
+					load_messages_insert(load_table, m->imp);
+				}
+			}
+		}
+	}
+}
+
+// Get the functions for string hashing
+#include "string_hash.h"
+
+static int class_compare(const char *name, const Class class)
+{
+	return string_compare(name, class->name);
+}
+static int class_hash(const Class class)
+{
+	return string_hash(class->name);
+}
+#define MAP_TABLE_NAME class_table_internal
+#define MAP_TABLE_COMPARE_FUNCTION class_compare
+#define MAP_TABLE_HASH_KEY string_hash
+#define MAP_TABLE_HASH_VALUE class_hash
+// This defines the maximum number of classes that the runtime supports.
+/*
+#define MAP_TABLE_STATIC_SIZE 2048
+#define MAP_TABLE_STATIC_NAME class_table
+*/
+#include "hash_table.h"
+
+static class_table_internal_table *class_table;
+
+
+#define unresolved_class_next subclass_list
+#define unresolved_class_prev sibling_class
+/**
+ * Linked list using the subclass_list pointer in unresolved classes.
+ */
+static Class unresolved_class_list;
+
+static enum objc_developer_mode_np mode;
+
+void objc_setDeveloperMode_np(enum objc_developer_mode_np newMode)
+{
+	mode = newMode;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Class table manipulation
+////////////////////////////////////////////////////////////////////////////////
+
+PRIVATE Class zombie_class;
+
+PRIVATE void class_table_insert(Class class)
+{
+	if (!objc_test_class_flag(class, objc_class_flag_resolved))
+	{
+		if (Nil != unresolved_class_list)
+		{
+			unresolved_class_list->unresolved_class_prev = class;
+		}
+		class->unresolved_class_next = unresolved_class_list;
+		unresolved_class_list = class;
+	}
+	if ((0 == zombie_class) && (strcmp("NSZombie", class->name) == 0))
+	{
+		zombie_class = class;
+	}
+	class_table_internal_insert(class_table, class);
+}
+
+PRIVATE Class class_table_get_safe(const char *class_name)
+{
+	if (NULL == class_name) { return Nil; }
+	return class_table_internal_table_get(class_table, class_name);
+}
+
+PRIVATE Class class_table_next(void **e)
+{
+	return class_table_internal_next(class_table,
+			(struct class_table_internal_table_enumerator**)e);
+}
+
+PRIVATE void init_class_tables(void)
+{
+	class_table_internal_initialize(&class_table, 4096);
+	objc_init_load_messages_table();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Loader functions
+////////////////////////////////////////////////////////////////////////////////
+
+PRIVATE BOOL objc_resolve_class(Class cls)
+{
+	// Skip this if the class is already resolved.
+	if (objc_test_class_flag(cls, objc_class_flag_resolved)) { return YES; }
+
+	// We can only resolve the class if its superclass is resolved.
+	if (cls->super_class)
+	{
+		Class super = (Class)objc_getClass((char*)cls->super_class);
+		if (Nil == super) { return NO; }
+
+		if (!objc_test_class_flag(super, objc_class_flag_resolved))
+		{
+			if (!objc_resolve_class(super))
+			{
+				return NO;
+			}
+		}
+	}
+
+
+	// Remove the class from the unresolved class list
+	if (Nil == cls->unresolved_class_prev)
+	{
+		unresolved_class_list = cls->unresolved_class_next;
+	}
+	else
+	{
+		cls->unresolved_class_prev->unresolved_class_next =
+			cls->unresolved_class_next;
+	}
+	if (Nil != cls->unresolved_class_next)
+	{
+		cls->unresolved_class_next->unresolved_class_prev =
+			cls->unresolved_class_prev;
+	}
+	cls->unresolved_class_prev = Nil;
+	cls->unresolved_class_next = Nil;
+
+	// The superclass for the metaclass.  This is the metaclass for the
+	// superclass if one exists, otherwise it is the root class itself
+	Class superMeta = Nil;
+	// The metaclass for the metaclass.  This is always the root class's
+	// metaclass.
+	Class metaMeta = Nil;
+
+	// Resolve the superclass pointer
+
+	if (NULL == cls->super_class)
+	{
+		superMeta = cls;
+		metaMeta = cls->isa;
+	}
+	else
+	{
+		// Resolve the superclass if it isn't already resolved
+		Class super = (Class)objc_getClass((char*)cls->super_class);
+		if (!objc_test_class_flag(super, objc_class_flag_resolved))
+		{
+			objc_resolve_class(super);
+		}
+		superMeta = super->isa;
+		// Set the superclass pointer for the class and the superclass
+		cls->super_class = super;
+		do
+		{
+			metaMeta = super->isa;
+			super = super->super_class;
+		} while (Nil != super);
+	}
+	Class meta = cls->isa;
+
+	// Make the root class the superclass of the metaclass (e.g. NSObject is
+	// the superclass of all metaclasses in classes that inherit from NSObject)
+	meta->super_class = superMeta;
+	meta->isa = metaMeta;
+
+	// Don't register root classes as children of anything
+	if (Nil != cls->super_class)
+	{
+		// Set up the class links
+		cls->sibling_class = cls->super_class->subclass_list;
+		cls->super_class->subclass_list = cls;
+	}
+	// Set up the metaclass links
+	meta->sibling_class = superMeta->subclass_list;
+	superMeta->subclass_list = meta;
+
+	// Mark this class (and its metaclass) as resolved
+	objc_set_class_flag(cls, objc_class_flag_resolved);
+	objc_set_class_flag(cls->isa, objc_class_flag_resolved);
+
+
+	// Fix up the ivar offsets
+	objc_compute_ivar_offsets(cls);
+	// Send the +load message, if required
+	objc_send_load_message(cls);
+	if (_objc_load_callback)
+	{
+		_objc_load_callback(cls, 0);
+	}
+	return YES;
+}
+
+PRIVATE void objc_resolve_class_links(void)
+{
+	LOCK_RUNTIME_FOR_SCOPE();
+	Class class = unresolved_class_list;
+	BOOL resolvedClass;
+	do
+	{
+		resolvedClass = NO;
+		while ((Nil != class))
+		{
+			Class next = class->unresolved_class_next;
+			objc_resolve_class(class);
+			if (resolvedClass ||
+				objc_test_class_flag(class, objc_class_flag_resolved))
+			{
+				resolvedClass = YES;
+			}
+			class = next;
+		}
+	} while (resolvedClass);
+}
+void __objc_resolve_class_links(void)
+{
+	static BOOL warned = NO;
+	if (!warned)
+	{
+		fprintf(stderr,
+			"Warning: Calling deprecated private ObjC runtime function %s\n", __func__);
+		warned = YES;
+	}
+	objc_resolve_class_links();
+}
+
+static void reload_class(struct objc_class *class, struct objc_class *old)
+{
+	const char *superclassName = (char*)class->super_class;
+	class->super_class = class_table_get_safe(superclassName);
+	// Checking the instance sizes are equal here is a quick-and-dirty test.
+	// It's not actually needed, because we're testing the ivars are at the
+	// same locations next, but it lets us skip those tests if the total size
+	// is different.
+	BOOL equalLayouts = (class->super_class == old->super_class) &&
+		(class->instance_size == old->instance_size);
+	// If either of the classes has an empty ivar list, then the other one must too.
+	if ((NULL == class->ivars) || (NULL == old->ivars))
+	{
+		equalLayouts &= (class->ivars == old->ivars);
+	}
+	else
+	{
+		// If the class sizes are the same, ensure that the ivars have the same
+		// types, names, and offsets.  Note: Renaming an ivar is treated as a
+		// conflict because name changes are often accompanied by semantic
+		// changes.  For example, an object ivar at offset 16 goes from being
+		// called 'delegate' to being called 'view' - we almost certainly don't
+		// want methods that expect to be working with the delegate ivar to
+		// work with the view ivar now!
+		for (int i=0 ; equalLayouts && (i<old->ivars->count) ; i++)
+		{
+			struct objc_ivar *oldIvar = &old->ivars->ivar_list[i];
+			struct objc_ivar *newIvar = &class->ivars->ivar_list[i];
+			equalLayouts &= strcmp(oldIvar->name, newIvar->name) == 0;
+			equalLayouts &= strcmp(oldIvar->type, newIvar->type) == 0;
+			equalLayouts &= (oldIvar->offset == newIvar->offset);
+		}
+	}
+
+	// If the layouts are equal, then we can simply tack the class's method
+	// list on to the front of the old class and update the dtable.
+	if (equalLayouts)
+	{
+		class->methods->next = old->methods;
+		old->methods = class->methods;
+		objc_update_dtable_for_class(old);
+		return;
+	}
+
+	// If we get to here, then we are adding a new class.  This is where things
+	// start to get a bit tricky...
+
+	// Ideally, we'd want to capture the subclass list here.  Unfortunately,
+	// this is not possible because the subclass will contain methods that
+	// refer to ivars in the superclass.
+	//
+	// We can't use the non-fragile ABI's offset facility easily, because we'd
+	// have to have two (or more) offsets for the same ivar.  This gets messy
+	// very quickly.  Ideally, we'd want every class to include ivar offsets
+	// for every single (public) ivar in its superclasses.  These could then be
+	// updated by copies of the class.  Defining a development ABI is something
+	// to consider for a future release.
+	class->subclass_list = NULL;
+
+	// Replace the old class with this one in the class table.  New lookups for
+	// this class will now return this class.
+	class_table_internal_table_set(class_table, (void*)class->name, class);
+
+	// Register all of the selectors used by this class and its metaclass
+	objc_register_selectors_from_class(class);
+	objc_register_selectors_from_class(class->isa);
+
+	// Set the uninstalled dtable.  The compiler could do this as well.
+	class->dtable = uninstalled_dtable;
+	class->isa->dtable = uninstalled_dtable;
+
+	// If this is a root class, make the class into the metaclass's superclass.
+	// This means that all instance methods will be available to the class.
+	if (NULL == superclassName)
+	{
+		class->isa->super_class = class;
+	}
+
+	if (class->protocols)
+	{
+		objc_init_protocols(class->protocols);
+	}
+}
+
+/**
+ * Loads a class.  This function assumes that the runtime mutex is locked.
+ */
+PRIVATE void objc_load_class(struct objc_class *class)
+{
+	struct objc_class *existingClass = class_table_get_safe(class->name);
+	if (Nil != existingClass)
+	{
+		if (objc_developer_mode_developer != mode)
+		{
+			fprintf(stderr,
+				"Loading two versions of %s.  The class that will be used is undefined\n",
+				class->name);
+			return;
+		}
+		reload_class(class, existingClass);
+		return;
+	}
+
+	// The compiler initialises the super class pointer to the name of the
+	// superclass, not the superclass pointer.
+	// Note: With the new ABI, the class pointer is public.  We could,
+	// therefore, directly reference the superclass from the compiler and make
+	// the linker resolve it.  This should be done in the GCC-incompatible ABI.
+	const char *superclassName = (char*)class->super_class;
+
+	// Work around a bug in some versions of GCC that don't initialize the
+	// class structure correctly.
+	class->subclass_list = NULL;
+
+	// Insert the class into the class table
+	class_table_insert(class);
+
+	// Register all of the selectors used by this class and its metaclass
+	objc_register_selectors_from_class(class);
+	objc_register_selectors_from_class(class->isa);
+
+	// Set the uninstalled dtable.  The compiler could do this as well.
+	class->dtable = uninstalled_dtable;
+	class->isa->dtable = uninstalled_dtable;
+
+	// If this is a root class, make the class into the metaclass's superclass.
+	// This means that all instance methods will be available to the class.
+	if (NULL == superclassName)
+	{
+		class->isa->super_class = class;
+	}
+
+	if (class->protocols)
+	{
+		objc_init_protocols(class->protocols);
+	}
+}
+
+PRIVATE Class SmallObjectClasses[7];
+
+BOOL objc_registerSmallObjectClass_np(Class class, uintptr_t mask)
+{
+	if ((mask & OBJC_SMALL_OBJECT_MASK) != mask)
+	{
+		return NO;
+	}
+	if (sizeof(void*) == 4)
+	{
+		if (Nil == SmallObjectClasses[0])
+		{
+			SmallObjectClasses[0] = class;
+			return YES;
+		}
+		return NO;
+	}
+	if (Nil != SmallObjectClasses[mask])
+	{
+		return NO;
+	}
+	SmallObjectClasses[mask] = class;
+	return YES;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Public API
+////////////////////////////////////////////////////////////////////////////////
+
+int objc_getClassList(Class *buffer, int bufferLen)
+{
+	if (buffer == NULL || bufferLen == 0)
+	{
+		return class_table->table_used;
+	}
+	int count = 0;
+	struct class_table_internal_table_enumerator *e = NULL;
+	Class next;
+	while (count < bufferLen &&
+		(next = class_table_internal_next(class_table, &e)))
+	{
+		buffer[count++] = next;
+	}
+	return count;
+}
+Class *objc_copyClassList(unsigned int *outCount)
+{
+	int count = class_table->table_used;
+	Class *buffer = calloc(sizeof(Class), count);
+	if (NULL != outCount)
+	{
+		*outCount = count;
+	}
+	objc_getClassList(buffer, count);
+	return buffer;
+}
+
+Class class_getSuperclass(Class cls)
+{
+	if (Nil == cls) { return Nil; }
+	if (!objc_test_class_flag(cls, objc_class_flag_resolved))
+	{
+		objc_resolve_class(cls);
+	}
+	return cls->super_class;
+}
+
+
+id objc_getClass(const char *name)
+{
+	id class = (id)class_table_get_safe(name);
+
+	if (nil != class) { return class; }
+
+	// Second chance lookup via @compatibilty_alias:
+	class = (id)alias_getClass(name);
+	if (nil != class) { return class; }
+
+	// Third chance lookup via the hook:
+	if (0 != _objc_lookup_class)
+	{
+		class = (id)_objc_lookup_class(name);
+	}
+
+	return class;
+}
+
+id objc_lookUpClass(const char *name)
+{
+	return (id)class_table_get_safe(name);
+}
+
+
+id objc_getMetaClass(const char *name)
+{
+	Class cls = (Class)objc_getClass(name);
+	return cls == Nil ? nil : (id)cls->isa;
+}
+
+// Legacy interface compatibility
+
+id objc_get_class(const char *name)
+{
+	return objc_getClass(name);
+}
+
+id objc_lookup_class(const char *name)
+{
+	return objc_getClass(name);
+}
+
+id objc_get_meta_class(const char *name)
+{
+	return objc_getMetaClass(name);
+}
+
+Class objc_next_class(void **enum_state)
+{
+  return class_table_next ( enum_state);
+}
+
+Class class_pose_as(Class impostor, Class super_class)
+{
+	fprintf(stderr, "Class posing is no longer supported.\n");
+	fprintf(stderr, "Please use class_replaceMethod() instead.\n");
+	abort();
+}
diff --git a/third_party/libobjc/constant_string.h b/third_party/libobjc/constant_string.h
new file mode 100644
index 0000000000000000000000000000000000000000..781a491c506d7bd283efbfcbe754309e18cbb617
--- /dev/null
+++ b/third_party/libobjc/constant_string.h
@@ -0,0 +1,7 @@
+#ifndef CONSTANT_STRING_CLASS
+#	ifdef GNUSTEP
+#		define CONSTANT_STRING_CLASS "NSConstantString"
+#	else
+#		define CONSTANT_STRING_CLASS "NXConstantString"
+#	endif
+#endif
diff --git a/third_party/libobjc/dtable.c b/third_party/libobjc/dtable.c
new file mode 100644
index 0000000000000000000000000000000000000000..a22351188771e22c0dea83e0db4b27377dcf7689
--- /dev/null
+++ b/third_party/libobjc/dtable.c
@@ -0,0 +1,734 @@
+#define __BSD_VISIBLE 1
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "objc/runtime.h"
+#include "sarray2.h"
+#include "selector.h"
+#include "class.h"
+#include "lock.h"
+#include "method_list.h"
+#include "slot_pool.h"
+#include "dtable.h"
+#include "visibility.h"
+
+PRIVATE dtable_t uninstalled_dtable;
+
+/** Head of the list of temporary dtables.  Protected by initialize_lock. */
+PRIVATE InitializingDtable *temporary_dtables;
+/** Lock used to protect the temporary dtables list. */
+PRIVATE mutex_t initialize_lock;
+/** The size of the largest dtable, rounded up to the nearest power of two. */
+static uint32_t dtable_depth = 8;
+
+struct objc_slot* objc_get_slot(Class cls, SEL selector);
+
+/**
+ * Returns YES if the class implements a method for the specified selector, NO
+ * otherwise.
+ */
+static BOOL ownsMethod(Class cls, SEL sel)
+{
+	struct objc_slot *slot = objc_get_slot(cls, sel);
+	if ((NULL != slot) && (slot->owner == cls))
+	{
+		return YES;
+	}
+	return NO;
+}
+
+/**
+ * Checks whether the class implements memory management methods, and whether
+ * they are safe to use with ARC.
+ */
+static void checkARCAccessors(Class cls)
+{
+	static SEL retain, release, autorelease, isARC;
+	if (NULL == retain)
+	{
+		retain = sel_registerName("retain");
+		release = sel_registerName("release");
+		autorelease = sel_registerName("autorelease");
+		isARC = sel_registerName("_ARCCompliantRetainRelease");
+	}
+	struct objc_slot *slot = objc_get_slot(cls, retain);
+	if ((NULL != slot) && !ownsMethod(slot->owner, isARC))
+	{
+		objc_clear_class_flag(cls, objc_class_flag_fast_arc);
+		return;
+	}
+	slot = objc_get_slot(cls, release);
+	if ((NULL != slot) && !ownsMethod(slot->owner, isARC))
+	{
+		objc_clear_class_flag(cls, objc_class_flag_fast_arc);
+		return;
+	}
+	slot = objc_get_slot(cls, autorelease);
+	if ((NULL != slot) && !ownsMethod(slot->owner, isARC))
+	{
+		objc_clear_class_flag(cls, objc_class_flag_fast_arc);
+		return;
+	}
+	objc_set_class_flag(cls, objc_class_flag_fast_arc);
+}
+
+static void collectMethodsForMethodListToSparseArray(
+		struct objc_method_list *list,
+		SparseArray *sarray,
+		BOOL recurse)
+{
+	if (recurse && (NULL != list->next))
+	{
+		collectMethodsForMethodListToSparseArray(list->next, sarray, YES);
+	}
+	for (unsigned i=0 ; i<list->count ; i++)
+	{
+		SparseArrayInsert(sarray, list->methods[i].selector->index,
+				(void*)&list->methods[i]);
+	}
+}
+
+
+#ifdef __OBJC_LOW_MEMORY__
+
+struct objc_dtable
+{
+	struct cache_line
+	{
+		uint32_t idx;
+		uint32_t version;
+		struct objc_slot *slot;
+	} cache[8];
+	mutex_t lock;
+	struct objc_slot **slots;
+	int slot_count;
+	int slot_size;
+	Class cls;
+};
+
+static void update_dtable(dtable_t dtable);
+
+PRIVATE void init_dispatch_tables ()
+{
+	INIT_LOCK(initialize_lock);
+}
+
+Class class_getSuperclass(Class);
+
+
+static dtable_t create_dtable_for_class(Class class, dtable_t root_dtable)
+{
+	// Don't create a dtable for a class that already has one
+	if (classHasDtable(class)) { return dtable_for_class(class); }
+
+	LOCK_RUNTIME_FOR_SCOPE();
+
+	// Make sure that another thread didn't create the dtable while we were
+	// waiting on the lock.
+	if (classHasDtable(class)) { return dtable_for_class(class); }
+
+	// Allocate the dtable
+	dtable_t dtable = calloc(1, sizeof(struct objc_dtable));
+	dtable->cls = class;
+	INIT_LOCK(dtable->lock);
+
+	// Initialise it
+	update_dtable(dtable);
+
+	return dtable;
+}
+
+
+PRIVATE void objc_resize_dtables(uint32_t newSize)
+{
+	if (1<<dtable_depth > newSize) { return; }
+	dtable_depth <<= 1;
+}
+
+#define HASH_UID(uid) ((uid >> 2) & 7)
+
+static struct objc_slot* check_cache(dtable_t dtable, uint32_t uid)
+{
+	int i = HASH_UID(uid);
+	volatile struct cache_line *cache = &dtable->cache[i];
+	int32_t initial_idx = cache->idx;
+
+	if (initial_idx != uid)
+	{
+		return NULL;
+	}
+
+	struct objc_slot *slot;
+	int32_t idx;
+	int32_t version;
+	do
+	{
+		initial_idx = cache->idx;
+		version = cache->version;
+		slot = cache->slot;
+		__sync_synchronize();
+		idx = cache->idx;
+	} while (idx != initial_idx);
+
+	return (idx == uid) && (slot->version == version) ? slot : NULL;
+}
+
+static struct objc_slot *find_slot(uint32_t uid, 
+		struct objc_slot **slots, int slot_count)
+{
+	if (slot_count == 0) { return NULL; }
+	int idx = slot_count >> 1;
+	struct objc_slot *slot = slots[idx];
+	if (slot_count == 1)
+	{
+		if (slot->selector->index == uid)
+		{
+			return slot;
+		}
+		return NULL;
+	}
+	if (slot->selector->index > uid)
+	{
+		return find_slot(uid, slots, idx);
+	}
+	if (slot->selector->index < uid)
+	{
+		return find_slot(uid, slots+idx, slot_count - idx);
+	}
+	if (slot->selector->index == uid)
+	{
+		return slot;
+	}
+	return NULL;
+}
+
+static int slot_cmp(const void *l, const void *r)
+{
+	return (*(struct objc_slot**)l)->selector->index
+	       - (*(struct objc_slot**)r)->selector->index;
+}
+
+static void insert_slot(dtable_t dtable, struct objc_slot *slot, uint32_t idx)
+{
+	if (dtable->slot_size == dtable->slot_count)
+	{
+		dtable->slot_size += 16;
+		dtable->slots = realloc(dtable->slots, dtable->slot_size *
+				sizeof(struct objc_slot));
+		assert(NULL != dtable->slots && "Out of memory!");
+	}
+	dtable->slots[dtable->slot_count++] = slot;
+}
+
+static void add_slot_to_dtable(SEL sel, dtable_t dtable, uint32_t
+		old_slot_count, struct objc_method *m, Class cls)
+{
+	uint32_t idx = sel->index;
+	struct objc_slot *s = find_slot(idx, dtable->slots, old_slot_count);
+	if (NULL != s)
+	{
+		s->method = m->imp;
+		s->version++;
+	}
+	else
+	{
+		struct objc_slot *slot = new_slot_for_method_in_class(m, cls);
+		slot->selector = sel;
+		insert_slot(dtable, slot, idx);
+		if (Nil != cls->super_class)
+		{
+			slot = objc_dtable_lookup(dtable_for_class(cls->super_class), idx);
+			if (NULL != slot)
+			{
+				slot->version++;
+			}
+		}
+	}
+}
+static void update_dtable(dtable_t dtable)
+{
+	Class cls = dtable->cls;
+
+	if (NULL == cls->methods) { return; }
+
+	SparseArray *methods = SparseArrayNewWithDepth(dtable_depth);
+	collectMethodsForMethodListToSparseArray((void*)cls->methods, methods, YES);
+
+	if (NULL == dtable->slots)
+	{
+		dtable->slots = calloc(sizeof(struct objc_slot), 16);
+		dtable->slot_size = 16;
+	}
+
+	uint32_t old_slot_count = dtable->slot_count;
+	struct objc_method *m;
+	uint32_t idx = 0;
+	while ((m = SparseArrayNext(methods, &idx)))
+	{
+		add_slot_to_dtable(m->selector, dtable, old_slot_count, m, cls);
+#ifdef TYPE_DEPENDENT_DISPATCH
+		add_slot_to_dtable(sel_getUntyped(m->selector), dtable, old_slot_count, m, cls);
+#endif
+	}
+	mergesort(dtable->slots, dtable->slot_count, sizeof(struct objc_slot*),
+			slot_cmp);
+	SparseArrayDestroy(methods);
+}
+
+PRIVATE void objc_update_dtable_for_class(Class cls)
+{
+	dtable_t dtable = dtable_for_class(cls);
+	// Be lazy about constructing the slot list - don't do it unless we actually
+	// need to access it
+	if ((NULL == dtable) || (NULL == dtable->slots)) { return; }
+
+	LOCK_FOR_SCOPE(&dtable->lock);
+
+	update_dtable(dtable);
+
+}
+PRIVATE void add_method_list_to_class(Class cls,
+                                      struct objc_method_list *list)
+{
+	objc_update_dtable_for_class(cls);
+}
+
+PRIVATE struct objc_slot* objc_dtable_lookup(dtable_t dtable, uint32_t uid)
+{
+	if (NULL == dtable) { return NULL; }
+
+	struct objc_slot *slot = check_cache(dtable, uid);
+	
+	if (NULL != slot)
+	{
+		return slot;
+	}
+
+	LOCK_FOR_SCOPE(&dtable->lock);
+	if (NULL == dtable->slots)
+	{
+		update_dtable(dtable);
+	}
+	slot = find_slot(uid, dtable->slots, dtable->slot_count);
+	if (NULL != slot)
+	{
+		int i = HASH_UID(uid);
+		volatile struct cache_line *cache = &dtable->cache[i];
+		// Simplified multiword atomic exchange.  First we write a value that
+		// is an invalid but recognisable UID and then a memory barrier.  Then
+		// we complete the update and set the index pointer if and only if
+		// there have been no other modifications in the meantime
+		cache->idx = -uid;
+		__sync_synchronize();
+		cache->version = slot->version;
+		cache->slot = slot;
+		__sync_bool_compare_and_swap(&cache->idx, -uid, uid);
+		return slot;
+	}
+
+	if (NULL != dtable->cls->super_class)
+	{
+		return objc_dtable_lookup(dtable_for_class(dtable->cls->super_class), uid);
+	}
+	return NULL;
+}
+PRIVATE dtable_t objc_copy_dtable_for_class(dtable_t old, Class cls)
+{
+	dtable_t dtable = calloc(1, sizeof(struct objc_dtable));
+	dtable->cls = cls;
+	INIT_LOCK(dtable->lock);
+	return dtable;
+}
+
+PRIVATE void free_dtable(dtable_t dtable)
+{
+	if (NULL != dtable->slots)
+	{
+		free(dtable->slots);
+	}
+	DESTROY_LOCK(&dtable->lock);
+	free(dtable);
+}
+
+#else
+
+
+PRIVATE void init_dispatch_tables ()
+{
+	INIT_LOCK(initialize_lock);
+	uninstalled_dtable = SparseArrayNewWithDepth(dtable_depth);
+}
+
+static BOOL installMethodInDtable(Class class,
+                                  Class owner,
+                                  SparseArray *dtable,
+                                  struct objc_method *method,
+                                  BOOL replaceExisting)
+{
+	ASSERT(uninstalled_dtable != dtable);
+	uint32_t sel_id = method->selector->index;
+	struct objc_slot *slot = SparseArrayLookup(dtable, sel_id);
+	if (NULL != slot)
+	{
+		// If this method is the one already installed, pretend to install it again.
+		if (slot->method == method->imp) { return NO; }
+
+		// If the existing slot is for this class, we can just replace the
+		// implementation.  We don't need to bump the version; this operation
+		// updates cached slots, it doesn't invalidate them.  
+		if (slot->owner == owner)
+		{
+			// Don't replace methods if we're not meant to (if they're from
+			// later in a method list, for example)
+			if (!replaceExisting) { return NO; }
+			slot->method = method->imp;
+			return YES;
+		}
+
+		// Check whether the owner of this method is a subclass of the one that
+		// owns this method.  If it is, then we don't want to install this
+		// method irrespective of other cases, because it has been overridden.
+		for (Class installedFor = slot->owner ;
+				Nil != installedFor ;
+				installedFor = installedFor->super_class)
+		{
+			if (installedFor == owner)
+			{
+				return NO;
+			}
+		}
+	}
+	struct objc_slot *oldSlot = slot;
+	slot = new_slot_for_method_in_class((void*)method, owner);
+	SparseArrayInsert(dtable, sel_id, slot);
+	// In TDD mode, we also register the first typed method that we
+	// encounter as the untyped version.
+#ifdef TYPE_DEPENDENT_DISPATCH
+	SparseArrayInsert(dtable, get_untyped_idx(method->selector), slot);
+#endif
+	// Invalidate the old slot, if there is one.
+	if (NULL != oldSlot)
+	{
+		oldSlot->version++;
+	}
+	return YES;
+}
+
+static void installMethodsInClass(Class cls,
+                                  Class owner,
+                                  SparseArray *methods,
+                                  BOOL replaceExisting)
+{
+	SparseArray *dtable = dtable_for_class(cls);
+	assert(uninstalled_dtable != dtable);
+
+	uint32_t idx = 0;
+	struct objc_method *m;
+	while ((m = SparseArrayNext(methods, &idx)))
+	{
+		if (!installMethodInDtable(cls, owner, dtable, m, replaceExisting))
+		{
+			// Remove this method from the list, if it wasn't actually installed
+			SparseArrayInsert(methods, idx, 0);
+		}
+	}
+}
+
+static void mergeMethodsFromSuperclass(Class super, Class cls, SparseArray *methods)
+{
+	for (struct objc_class *subclass=cls->subclass_list ; 
+		Nil != subclass ; subclass = subclass->sibling_class)
+	{
+		// Don't bother updating dtables for subclasses that haven't been
+		// initialized yet
+		if (!classHasDtable(subclass)) { continue; }
+
+		// Create a new (copy-on-write) array to pass down to children
+		SparseArray *newMethods = SparseArrayCopy(methods);
+		// Install all of these methods except ones that are overridden in the
+		// subclass.  All of the methods that we are updating were added in a
+		// superclass, so we don't replace versions registered to the subclass.
+		installMethodsInClass(subclass, super, newMethods, YES);
+		// Recursively add the methods to the subclass's subclasses.
+		mergeMethodsFromSuperclass(super, subclass, newMethods);
+		SparseArrayDestroy(newMethods);
+	}
+}
+
+Class class_getSuperclass(Class);
+
+PRIVATE void objc_update_dtable_for_class(Class cls)
+{
+	// Only update real dtables
+	if (!classHasDtable(cls)) { return; }
+
+	LOCK_RUNTIME_FOR_SCOPE();
+
+	SparseArray *methods = SparseArrayNewWithDepth(dtable_depth);
+	collectMethodsForMethodListToSparseArray((void*)cls->methods, methods, YES);
+	installMethodsInClass(cls, cls, methods, YES);
+	// Methods now contains only the new methods for this class.
+	mergeMethodsFromSuperclass(cls, cls, methods);
+	SparseArrayDestroy(methods);
+	checkARCAccessors(cls);
+}
+
+PRIVATE void add_method_list_to_class(Class cls,
+                                      struct objc_method_list *list)
+{
+	// Only update real dtables
+	if (!classHasDtable(cls)) { return; }
+
+	LOCK_RUNTIME_FOR_SCOPE();
+
+	SparseArray *methods = SparseArrayNewWithDepth(dtable_depth);
+	collectMethodsForMethodListToSparseArray(list, methods, NO);
+	installMethodsInClass(cls, cls, methods, YES);
+	// Methods now contains only the new methods for this class.
+	mergeMethodsFromSuperclass(cls, cls, methods);
+	SparseArrayDestroy(methods);
+	checkARCAccessors(cls);
+}
+
+static dtable_t create_dtable_for_class(Class class, dtable_t root_dtable)
+{
+	// Don't create a dtable for a class that already has one
+	if (classHasDtable(class)) { return dtable_for_class(class); }
+
+	LOCK_RUNTIME_FOR_SCOPE();
+
+	// Make sure that another thread didn't create the dtable while we were
+	// waiting on the lock.
+	if (classHasDtable(class)) { return dtable_for_class(class); }
+
+	Class super = class_getSuperclass(class);
+	dtable_t dtable;
+
+
+	if (Nil == super)
+	{
+		dtable = SparseArrayNewWithDepth(dtable_depth);
+	}
+	else
+	{
+		dtable_t super_dtable = dtable_for_class(super);
+		if (super_dtable == uninstalled_dtable)
+		{
+			if (super->isa == class)
+			{
+				super_dtable = root_dtable;
+			}
+			else
+			{
+				abort();
+			}
+		}
+		dtable = SparseArrayCopy(super_dtable);
+	}
+
+	// When constructing the initial dtable for a class, we iterate along the
+	// method list in forward-traversal order.  The first method that we
+	// encounter is always the one that we want to keep, so we instruct
+	// installMethodInDtable() not to replace methods that are already
+	// associated with this class.
+	struct objc_method_list *list = (void*)class->methods;
+
+	while (NULL != list)
+	{
+		for (unsigned i=0 ; i<list->count ; i++)
+		{
+			installMethodInDtable(class, class, dtable, &list->methods[i], NO);
+		}
+		list = list->next;
+	}
+
+	return dtable;
+}
+
+
+Class class_table_next(void **e);
+
+PRIVATE void objc_resize_dtables(uint32_t newSize)
+{
+	// If dtables already have enough space to store all registered selectors, do nothing
+	if (1<<dtable_depth > newSize) { return; }
+
+	LOCK_RUNTIME_FOR_SCOPE();
+
+	dtable_depth <<= 1;
+
+	uint32_t oldMask = uninstalled_dtable->mask;
+
+	SparseArrayExpandingArray(uninstalled_dtable);
+	// Resize all existing dtables
+	void *e = NULL;
+	struct objc_class *next;
+	while ((next = class_table_next(&e)))
+	{
+		if (next->dtable != (void*)uninstalled_dtable && 
+			NULL != next->dtable &&
+			((SparseArray*)next->dtable)->mask == oldMask)
+		{
+			SparseArrayExpandingArray((void*)next->dtable);
+		}
+	}
+}
+
+PRIVATE dtable_t objc_copy_dtable_for_class(dtable_t old, Class cls)
+{
+	return SparseArrayCopy(old);
+}
+
+PRIVATE void free_dtable(dtable_t dtable)
+{
+	SparseArrayDestroy(dtable);
+}
+
+#endif // __OBJC_LOW_MEMORY__
+
+LEGACY void update_dispatch_table_for_class(Class cls)
+{
+	static BOOL warned = NO;
+	if (!warned)
+	{
+		fprintf(stderr, 
+			"Warning: Calling deprecated private ObjC runtime function %s\n", __func__);
+		warned = YES;
+	}
+	objc_update_dtable_for_class(cls);
+}
+
+void objc_resolve_class(Class);
+
+__attribute__((unused)) static void objc_release_object_lock(id *x)
+{
+	objc_sync_exit(*x);
+}
+/**
+ * Macro that is equivalent to @synchronize, for use in C code.
+ */
+#define LOCK_OBJECT_FOR_SCOPE(obj) \
+	__attribute__((cleanup(objc_release_object_lock)))\
+	__attribute__((unused)) id lock_object_pointer = obj;\
+	objc_sync_enter(obj);
+
+/**
+ * Remove a buffer from an entry in the initializing dtables list.  This is
+ * called as a cleanup to ensure that it runs even if +initialize throws an
+ * exception.
+ */
+static void remove_dtable(InitializingDtable* meta_buffer)
+{
+	LOCK(&initialize_lock);
+	InitializingDtable *buffer = meta_buffer->next;
+	// Install the dtable:
+	meta_buffer->class->dtable = meta_buffer->dtable;
+	buffer->class->dtable = buffer->dtable;
+	// Remove the look-aside buffer entry.
+	if (temporary_dtables == meta_buffer)
+	{
+		temporary_dtables = buffer->next;
+	}
+	else
+	{
+		InitializingDtable *prev = temporary_dtables;
+		while (prev->next->class != meta_buffer->class)
+		{
+			prev = prev->next;
+		}
+		prev->next = buffer->next;
+	}
+	UNLOCK(&initialize_lock);
+}
+
+/**
+ * Send a +initialize message to the receiver, if required.  
+ */
+PRIVATE void objc_send_initialize(id object)
+{
+	Class class = classForObject(object);
+	// If the first message is sent to an instance (weird, but possible and
+	// likely for things like NSConstantString, make sure +initialize goes to
+	// the class not the metaclass.  
+	if (objc_test_class_flag(class, objc_class_flag_meta))
+	{
+		class = (Class)object;
+	}
+	Class meta = class->isa;
+
+
+	// Make sure that the class is resolved.
+	objc_resolve_class(class);
+
+	// Make sure that the superclass is initialized first.
+	if (Nil != class->super_class)
+	{
+		objc_send_initialize((id)class->super_class);
+	}
+
+	LOCK(&initialize_lock);
+
+	// Superclass +initialize might possibly send a message to this class, in
+	// which case this method would be called again.  See NSObject and
+	// NSAutoreleasePool +initialize interaction in GNUstep.
+	if (objc_test_class_flag(class, objc_class_flag_initialized))
+	{
+		UNLOCK(&initialize_lock);
+		// We know that initialization has started because the flag is set.
+		// Check that it's finished by grabbing the class lock.  This will be
+		// released once the class has been fully initialized
+		objc_sync_enter((id)meta);
+		objc_sync_exit((id)meta);
+		assert(dtable_for_class(class) != uninstalled_dtable);
+		return;
+	}
+
+	LOCK_OBJECT_FOR_SCOPE((id)meta);
+
+	// Set the initialized flag on both this class and its metaclass, to make
+	// sure that +initialize is only ever sent once.
+	objc_set_class_flag(class, objc_class_flag_initialized);
+	objc_set_class_flag(meta, objc_class_flag_initialized);
+
+	dtable_t class_dtable = create_dtable_for_class(class, uninstalled_dtable);
+	dtable_t dtable = create_dtable_for_class(meta, class_dtable);
+
+	static SEL initializeSel = 0;
+	if (0 == initializeSel)
+	{
+		initializeSel = sel_registerName("initialize");
+	}
+
+	struct objc_slot *initializeSlot = 
+		objc_dtable_lookup(dtable, initializeSel->index);
+
+	// If there's no initialize method, then don't bother installing and
+	// removing the initialize dtable, just install both dtables correctly now
+	if (0 == initializeSlot)
+	{
+		meta->dtable = dtable;
+		class->dtable = class_dtable;
+		checkARCAccessors(class);
+		UNLOCK(&initialize_lock);
+		return;
+	}
+
+
+
+	// Create an entry in the dtable look-aside buffer for this.  When sending
+	// a message to this class in future, the lookup function will check this
+	// buffer if the receiver's dtable is not installed, and block if
+	// attempting to send a message to this class.
+	InitializingDtable buffer = { class, class_dtable, temporary_dtables };
+	__attribute__((cleanup(remove_dtable)))
+	InitializingDtable meta_buffer = { meta, dtable, &buffer };
+	temporary_dtables = &meta_buffer;
+	UNLOCK(&initialize_lock);
+
+	checkARCAccessors(class);
+
+	// Store the buffer in the temporary dtables list.  Note that it is safe to
+	// insert it into a global list, even though it's a temporary variable,
+	// because we will clean it up after this function.
+	initializeSlot->method((id)class, initializeSel);
+}
diff --git a/third_party/libobjc/dtable.h b/third_party/libobjc/dtable.h
new file mode 100644
index 0000000000000000000000000000000000000000..95eae20888572f815216831d6093fef0d5c3b754
--- /dev/null
+++ b/third_party/libobjc/dtable.h
@@ -0,0 +1,128 @@
+#include "lock.h"
+#include "class.h"
+#include "sarray2.h"
+#include "objc/slot.h"
+#include "visibility.h"
+#include <stdint.h>
+#include <stdio.h>
+
+#ifdef __OBJC_LOW_MEMORY__
+typedef struct objc_dtable* dtable_t;
+struct objc_slot* objc_dtable_lookup(dtable_t dtable, uint32_t uid);
+#else
+typedef SparseArray* dtable_t;
+#	define objc_dtable_lookup SparseArrayLookup
+#endif
+
+/**
+ * Pointer to the sparse array representing the pretend (uninstalled) dtable.
+ */
+PRIVATE extern dtable_t uninstalled_dtable;
+/**
+ * Structure for maintaining a linked list of temporary dtables.  When sending
+ * an +initialize message to a class, we create a temporary dtables and store
+ * it in a linked list.  This is then used when sending other messages to
+ * instances of classes in the middle of initialisation.
+ */
+typedef struct _InitializingDtable
+{
+	/** The class that owns the dtable. */
+	Class class;
+	/** The dtable for this class. */
+	dtable_t dtable;
+	/** The next uninstalled dtable in the list. */
+	struct _InitializingDtable *next;
+} InitializingDtable;
+
+/** Head of the list of temporary dtables.  Protected by initialize_lock. */
+extern InitializingDtable *temporary_dtables;
+extern mutex_t initialize_lock;
+
+/**
+ * Returns whether a class has an installed dtable.
+ */
+static inline int classHasInstalledDtable(struct objc_class *cls)
+{
+	return (cls->dtable != uninstalled_dtable);
+}
+
+int objc_sync_enter(id object);
+int objc_sync_exit(id object);
+/**
+ * Returns the dtable for a given class.  If we are currently in an +initialize
+ * method then this will block if called from a thread other than the one
+ * running the +initialize method.  
+ */
+static inline dtable_t dtable_for_class(Class cls)
+{
+	if (classHasInstalledDtable(cls))
+	{
+		return cls->dtable;
+	}
+
+	dtable_t dtable = uninstalled_dtable;
+
+	{
+		LOCK_FOR_SCOPE(&initialize_lock);
+		if (classHasInstalledDtable(cls))
+		{
+			return cls->dtable;
+		}
+		/* This is a linear search, and so, in theory, could be very slow.  It
+		 * is O(n) where n is the number of +initialize methods on the stack.
+		 * In practice, this is a very small number.  Profiling with GNUstep
+		 * showed that this peaks at 8. */
+		InitializingDtable *buffer = temporary_dtables;
+		while (NULL != buffer)
+		{
+			if (buffer->class == cls)
+			{
+				dtable = buffer->dtable;
+				break;
+			}
+			buffer = buffer->next;
+		}
+	}
+
+	if (dtable != uninstalled_dtable)
+	{
+		// Make sure that we block if +initialize is still running.  We do this
+		// after we've released the initialize lock, so that the real dtable
+		// can be installed.  This acquires / releases a recursive mutex, so if
+		// this mutex is already held by this thread then this will proceed
+		// immediately.  If it's held by another thread (i.e. the one running
+		// +initialize) then we block here until it's run.  We don't need to do
+		// this if the dtable is the uninstalled dtable, because that means
+		// +initialize has not yet been sent, so we can wait until something
+		// triggers it before needing any synchronisation.
+		objc_sync_enter((id)cls);
+		objc_sync_exit((id)cls);
+	}
+	return dtable;
+}
+
+/**
+ * Returns whether a class has had a dtable created.  The dtable may be
+ * installed, or stored in the look-aside buffer.
+ */
+static inline int classHasDtable(struct objc_class *cls)
+{
+	return (dtable_for_class(cls) != uninstalled_dtable);
+}
+
+/**
+ * Updates the dtable for a class and its subclasses.  Must be called after
+ * modifying a class's method list.
+ */
+void objc_update_dtable_for_class(Class);
+/**
+ * Adds a single method list to a class.  This is used when loading categories,
+ * and is faster than completely rebuilding the dtable.
+ */
+void add_method_list_to_class(Class cls,
+                              struct objc_method_list *list);
+
+/**
+ * Destroys a dtable.
+ */
+void free_dtable(dtable_t dtable);
diff --git a/third_party/libobjc/dwarf_eh.h b/third_party/libobjc/dwarf_eh.h
new file mode 100644
index 0000000000000000000000000000000000000000..6dbe1e6d83140fcef085aa792f93e06485233e0e
--- /dev/null
+++ b/third_party/libobjc/dwarf_eh.h
@@ -0,0 +1,323 @@
+/**
+ * This file is Copyright PathScale 2010.  Permission granted to distribute
+ * according to the terms of the MIT license (see COPYING.MIT)
+ */
+#include <assert.h>
+#include <stdint.h>
+
+// _GNU_SOURCE must be defined for unwind.h to expose some of the functions
+// that we want.  If it isn't, then we define it and undefine it to make sure
+// that it doesn't impact the rest of the program.
+#ifndef _GNU_SOURCE
+#	define _GNU_SOURCE 1
+#	include "unwind.h"
+#	undef _GNU_SOURCE
+#else
+#	include "unwind.h"
+#endif
+
+/**
+ * Type used to store pointers to values computed by DWARF expressions.
+ */
+typedef unsigned char *dw_eh_ptr_t;
+// Flag indicating a signed quantity
+#define DW_EH_PE_signed 0x08
+/// DWARF data encoding types
+enum dwarf_data_encoding
+{
+	// Unsigned, little-endian, base 128-encoded (variable length)
+	DW_EH_PE_uleb128 = 0x01,
+	// uint16
+	DW_EH_PE_udata2  = 0x02,
+	// uint32
+	DW_EH_PE_udata4  = 0x03,
+	// uint64
+	DW_EH_PE_udata8  = 0x04,
+	// Signed versions of the above:
+	DW_EH_PE_sleb128 = DW_EH_PE_uleb128 | DW_EH_PE_signed,
+	DW_EH_PE_sdata2  = DW_EH_PE_udata2 | DW_EH_PE_signed,
+	DW_EH_PE_sdata4  = DW_EH_PE_udata4 | DW_EH_PE_signed,
+	DW_EH_PE_sdata8  = DW_EH_PE_udata8 | DW_EH_PE_signed
+};
+
+static inline enum dwarf_data_encoding get_encoding(unsigned char x)
+{
+	return (enum dwarf_data_encoding)(x & 0xf);
+}
+
+enum dwarf_data_relative
+{
+	// Value is omitted
+	DW_EH_PE_omit     = 0xff,
+	// Absolute pointer value
+	DW_EH_PE_absptr   = 0x00,
+	// Value relative to program counter
+	DW_EH_PE_pcrel    = 0x10,
+	// Value relative to the text segment
+	DW_EH_PE_textrel  = 0x20,
+	// Value relative to the data segment
+	DW_EH_PE_datarel  = 0x30,
+	// Value relative to the start of the function
+	DW_EH_PE_funcrel  = 0x40,
+	// Aligned pointer (Not supported yet - are they actually used?)
+	DW_EH_PE_aligned  = 0x50,
+	// Pointer points to address of real value
+	DW_EH_PE_indirect = 0x80
+};
+static inline enum dwarf_data_relative get_base(unsigned char x)
+{
+	return (enum dwarf_data_relative)(x & 0x70);
+}
+static int is_indirect(unsigned char x)
+{
+	return (x & DW_EH_PE_indirect);
+}
+
+static inline int dwarf_size_of_fixed_size_field(unsigned char type)
+{
+	// Low three bits indicate size...
+	switch (type & 7)
+	{
+		case DW_EH_PE_udata2: return 2;
+		case DW_EH_PE_udata4: return 4;
+		case DW_EH_PE_udata8: return 8;
+		case DW_EH_PE_absptr: return sizeof(void*);
+	}
+	abort();
+}
+
+/** 
+ * Read an unsigned, little-endian, base-128, DWARF value.  Updates *data to
+ * point to the end of the value.
+ */
+static uint64_t read_leb128(unsigned char** data, int *b)
+{
+	uint64_t uleb = 0;
+	unsigned int bit = 0;
+	unsigned char digit = 0;
+	// We have to read at least one octet, and keep reading until we get to one
+	// with the high bit unset
+	do
+	{
+		// This check is a bit too strict - we should also check the highest
+		// bit of the digit.
+		assert(bit < sizeof(uint64_t) * 8);
+		// Get the base 128 digit 
+		digit = (**data) & 0x7f;
+		// Add it to the current value
+		uleb += digit << bit;
+		// Increase the shift value
+		bit += 7;
+		// Proceed to the next octet
+		(*data)++;
+		// Terminate when we reach a value that does not have the high bit set
+		// (i.e. which was not modified when we mask it with 0x7f)
+	} while ((*(*data - 1)) != digit);
+	*b = bit;
+
+	return uleb;
+}
+
+static int64_t read_uleb128(unsigned char** data)
+{
+	int b;
+	return read_leb128(data, &b);
+}
+
+
+static int64_t read_sleb128(unsigned char** data)
+{
+	int bits;
+	// Read as if it's signed
+	uint64_t uleb = read_leb128(data, &bits);
+	// If the most significant bit read is 1, then we need to sign extend it
+	if (uleb >> (bits-1) == 1)
+	{
+		// Sign extend by setting all bits in front of it to 1
+		uleb |= ((int64_t)-1) << bits;
+	}
+	return (int64_t)uleb;
+}
+
+static uint64_t read_value(char encoding, unsigned char **data)
+{
+	enum dwarf_data_encoding type = get_encoding(encoding);
+	uint64_t v;
+	switch ((int)type)
+	{
+		// Read fixed-length types
+#define READ(dwarf, type) \
+		case dwarf:\
+			v = (uint64_t)(*(type*)(*data));\
+			*data += sizeof(type);\
+			break;
+		READ(DW_EH_PE_udata2, uint16_t)
+		READ(DW_EH_PE_udata4, uint32_t)
+		READ(DW_EH_PE_udata8, uint64_t)
+		READ(DW_EH_PE_sdata2, int16_t)
+		READ(DW_EH_PE_sdata4, int32_t)
+		READ(DW_EH_PE_sdata8, int64_t)
+		case DW_EH_PE_absptr:
+			v = (uint64_t)(*(intptr_t*)(*data));
+			*data += sizeof(intptr_t);
+			break;
+		//READ(DW_EH_PE_absptr, intptr_t)
+#undef READ
+		case DW_EH_PE_sleb128:
+			v = read_sleb128(data);
+			break;
+		case DW_EH_PE_uleb128:
+			v = read_uleb128(data);
+			break;
+		default: abort();
+	}
+
+	return v;
+}
+
+static uint64_t resolve_indirect_value(struct _Unwind_Context *c, unsigned char encoding, int64_t v, dw_eh_ptr_t start)
+{
+	switch (get_base(encoding))
+	{
+		case DW_EH_PE_pcrel:
+			v += (uint64_t)(uintptr_t)start;
+			break;
+		case DW_EH_PE_textrel:
+			v += (uint64_t)(uintptr_t)_Unwind_GetTextRelBase(c);
+			break;
+		case DW_EH_PE_datarel:
+			v += (uint64_t)(uintptr_t)_Unwind_GetDataRelBase(c);
+			break;
+		case DW_EH_PE_funcrel:
+			v += (uint64_t)(uintptr_t)_Unwind_GetRegionStart(c);
+		default:
+			break;
+	}
+	// If this is an indirect value, then it is really the address of the real
+	// value
+	// TODO: Check whether this should really always be a pointer - it seems to
+	// be a GCC extensions, so not properly documented...
+	if (is_indirect(encoding))
+	{
+		v = (uint64_t)(uintptr_t)*(void**)(uintptr_t)v;
+	}
+	return v;
+}
+
+
+static inline void read_value_with_encoding(struct _Unwind_Context *context,
+                                            dw_eh_ptr_t *data,
+                                            uint64_t *out)
+{
+	dw_eh_ptr_t start = *data;
+	unsigned char encoding = *((*data)++);
+	// If this value is omitted, skip it and don't touch the output value
+	if (encoding == DW_EH_PE_omit) { return; }
+
+	*out = read_value(encoding, data);
+	*out = resolve_indirect_value(context, encoding, *out, start);
+}
+
+
+struct dwarf_eh_lsda
+{
+	dw_eh_ptr_t region_start;
+	dw_eh_ptr_t landing_pads;
+	dw_eh_ptr_t type_table;
+	unsigned char type_table_encoding;
+	dw_eh_ptr_t call_site_table;
+	dw_eh_ptr_t action_table;
+	unsigned char callsite_encoding;
+};
+
+static inline struct dwarf_eh_lsda parse_lsda(struct _Unwind_Context *context, unsigned char *data)
+{
+	struct dwarf_eh_lsda lsda;
+
+	lsda.region_start = (dw_eh_ptr_t)(uintptr_t)_Unwind_GetRegionStart(context);
+
+	// If the landing pads are relative to anything other than the start of
+	// this region, find out where.  This is @LPStart in the spec, although the
+	// encoding that GCC uses does not quite match the spec.
+	uint64_t v = (uint64_t)(uintptr_t)lsda.region_start;
+	read_value_with_encoding(context, &data, &v);
+	lsda.landing_pads = (dw_eh_ptr_t)(uintptr_t)v;
+
+	// If there is a type table, find out where it is.  This is @TTBase in the
+	// spec.  Note: we find whether there is a type table pointer by checking
+	// whether the leading byte is DW_EH_PE_omit (0xff), which is not what the
+	// spec says, but does seem to be how G++ indicates this.
+	lsda.type_table = 0;
+	lsda.type_table_encoding = *data++;
+	if (lsda.type_table_encoding != DW_EH_PE_omit)
+	{
+		v = read_uleb128(&data);
+		dw_eh_ptr_t type_table = data;
+		type_table += v;
+		lsda.type_table = type_table;
+		//lsda.type_table = (uintptr_t*)(data + v);
+	}
+
+	lsda.callsite_encoding = (enum dwarf_data_encoding)(*(data++));
+
+	// Action table is immediately after the call site table
+	lsda.action_table = data;
+	uintptr_t callsite_size = (uintptr_t)read_uleb128(&data);
+	lsda.action_table = data + callsite_size;
+	// Call site table is immediately after the header
+	lsda.call_site_table = (dw_eh_ptr_t)data;
+
+
+	return lsda;
+}
+
+struct dwarf_eh_action
+{
+	dw_eh_ptr_t landing_pad;
+	dw_eh_ptr_t action_record;
+};
+
+/**
+ * Look up the landing pad that corresponds to the current invoke.
+ */
+__attribute__((unused))
+static struct dwarf_eh_action 
+	dwarf_eh_find_callsite(struct _Unwind_Context *context, struct dwarf_eh_lsda *lsda)
+{
+	struct dwarf_eh_action result = { 0, 0};
+	uint64_t ip = _Unwind_GetIP(context) - _Unwind_GetRegionStart(context);
+	unsigned char *callsite_table = (unsigned char*)lsda->call_site_table;
+	while (callsite_table <= lsda->action_table)
+	{
+		// Once again, the layout deviates from the spec.
+		uint64_t call_site_start, call_site_size, landing_pad, action;
+		call_site_start = read_value(lsda->callsite_encoding, &callsite_table);
+		call_site_size = read_value(lsda->callsite_encoding, &callsite_table);
+
+		// Call site entries are started
+		if (call_site_start > ip) { break; }
+
+		landing_pad = read_value(lsda->callsite_encoding, &callsite_table);
+		action = read_uleb128(&callsite_table);
+
+		if (call_site_start <= ip && ip <= call_site_start + call_site_size)
+		{
+			if (action)
+			{
+				// Action records are 1-biased so both no-record and zeroth
+				// record can be stored.
+				result.action_record = lsda->action_table + action - 1;
+			}
+			// No landing pad means keep unwinding.
+			if (landing_pad)
+			{
+				// Landing pad is the offset from the value in the header
+				result.landing_pad = lsda->landing_pads + landing_pad;
+			}
+			break;
+		}
+	}
+	return result;
+}
+
+#define EXCEPTION_CLASS(a,b,c,d,e,f,g,h) (((uint64_t)a << 56) + ((uint64_t)b << 48) + ((uint64_t)c << 40) + ((uint64_t)d << 32) + ((uint64_t)e << 24) + ((uint64_t)f << 16) + ((uint64_t)g << 8) + ((uint64_t)h))
diff --git a/third_party/libobjc/eh_personality.c b/third_party/libobjc/eh_personality.c
new file mode 100644
index 0000000000000000000000000000000000000000..e3e4ead29c5cbdf8e7f08aa649539b2d30c4c9ae
--- /dev/null
+++ b/third_party/libobjc/eh_personality.c
@@ -0,0 +1,449 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "dwarf_eh.h"
+#include "objc/runtime.h"
+#include "objc/hooks.h"
+#include "class.h"
+#include "objcxx_eh.h"
+
+#define fprintf(...)
+
+/**
+ * Class of exceptions to distinguish between this and other exception types.
+ */
+static const uint64_t objc_exception_class = EXCEPTION_CLASS('G','N','U','C','O','B','J','C');
+static const uint64_t cxx_exception_class = EXCEPTION_CLASS('G','N','U','C','C','+','+','\0');
+
+/**
+ * Structure used as a header on thrown exceptions.  
+ */
+struct objc_exception
+{
+	/** The selector value to be returned when installing the catch handler.
+	 * Used at the call site to determine which catch() block should execute.
+	 * This is found in phase 1 of unwinding then installed in phase 2.*/
+	int handlerSwitchValue;
+	/** The cached landing pad for the catch handler.*/
+	void *landingPad;
+
+	/** The language-agnostic part of the exception header. */
+	struct _Unwind_Exception unwindHeader;
+	/** Thrown object.  This is after the unwind header so that the C++
+	 * exception handler can catch this as a foreign exception. */
+	id object;
+	/** C++ exception structure.  Used for mixed exceptions.  When we are in
+	 * Objective-C++ code, we create this structure for passing to the C++
+	 * exception personality function.  It will then handle installing
+	 * exceptions for us.  */
+	struct _Unwind_Exception *cxx_exception;
+};
+
+typedef enum
+{
+	handler_none,
+	handler_cleanup,
+	handler_catchall_id,
+	handler_catchall,
+	handler_class
+} handler_type;
+
+/**
+ * Saves the result of the landing pad that we have found.  For ARM, this is
+ * stored in the generic unwind structure, while on other platforms it is
+ * stored in the Objective-C exception.
+ */
+static void saveLandingPad(struct _Unwind_Context *context,
+                           struct _Unwind_Exception *ucb,
+                           struct objc_exception *ex,
+                           int selector,
+                           dw_eh_ptr_t landingPad)
+{
+#ifdef __arm__
+	// On ARM, we store the saved exception in the generic part of the structure
+	ucb->barrier_cache.sp = _Unwind_GetGR(context, 13);
+	ucb->barrier_cache.bitpattern[1] = (uint32_t)selector;
+	ucb->barrier_cache.bitpattern[3] = (uint32_t)landingPad;
+#else
+	// Cache the results for the phase 2 unwind, if we found a handler
+	// and this is not a foreign exception.  We can't cache foreign exceptions
+	// because we don't know their structure (although we could cache C++
+	// exceptions...)
+	if (ex)
+	{
+		ex->handlerSwitchValue = selector;
+		ex->landingPad = landingPad;
+	}
+#endif
+}
+
+/**
+ * Loads the saved landing pad.  Returns 1 on success, 0 on failure.
+ */
+static int loadLandingPad(struct _Unwind_Context *context,
+                          struct _Unwind_Exception *ucb,
+                          struct objc_exception *ex,
+                          unsigned long *selector,
+                          dw_eh_ptr_t *landingPad)
+{
+#ifdef __arm__
+	*selector = ucb->barrier_cache.bitpattern[1];
+	*landingPad = (dw_eh_ptr_t)ucb->barrier_cache.bitpattern[3];
+	return 1;
+#else
+	if (ex)
+	{
+		*selector = ex->handlerSwitchValue;
+		*landingPad = ex->landingPad;
+		return 0;
+	}
+	return 0;
+#endif
+}
+
+static inline _Unwind_Reason_Code continueUnwinding(struct _Unwind_Exception *ex,
+                                                    struct _Unwind_Context *context)
+{
+#ifdef __arm__
+	if (__gnu_unwind_frame(ex, context) != _URC_OK) { return _URC_FAILURE; }
+#endif
+	return _URC_CONTINUE_UNWIND;
+}
+
+static void cleanup(_Unwind_Reason_Code reason, struct _Unwind_Exception *e)
+{
+	/*
+  if (header->exceptionDestructor)
+		  header->exceptionDestructor (e + 1);
+
+	free((struct objc_exception*) ((char*)e - offsetof(struct objc_exception,
+					unwindHeader)));
+					*/
+}
+/**
+ * Throws an Objective-C exception.  This function is, unfortunately, used for
+ * rethrowing caught exceptions too, even in @finally() blocks.  Unfortunately,
+ * this means that we have some problems if the exception is boxed.
+ */
+void objc_exception_throw(id object)
+{
+
+	SEL rethrow_sel = sel_registerName("rethrow");
+	if ((nil != object) &&
+	    (class_respondsToSelector(classForObject(object), rethrow_sel)))
+	{
+		fprintf(stderr, "Rethrowing\n");
+		IMP rethrow = objc_msg_lookup(object, rethrow_sel);
+		rethrow(object, rethrow_sel);
+		// Should not be reached!  If it is, then the rethrow method actually
+		// didn't, so we throw it normally.
+	}
+
+	fprintf(stderr, "Throwing %p\n", object);
+
+	struct objc_exception *ex = calloc(1, sizeof(struct objc_exception));
+
+	ex->unwindHeader.exception_class = objc_exception_class;
+	ex->unwindHeader.exception_cleanup = cleanup;
+
+	ex->object = object;
+
+	_Unwind_Reason_Code err = _Unwind_RaiseException(&ex->unwindHeader);
+	free(ex);
+	if (_URC_END_OF_STACK == err && 0 != _objc_unexpected_exception)
+	{
+		_objc_unexpected_exception(object);
+	}
+	fprintf(stderr, "Throw returned %d\n",(int) err);
+	abort();
+}
+
+static Class get_type_table_entry(struct _Unwind_Context *context,
+                                  struct dwarf_eh_lsda *lsda,
+                                  int filter)
+{
+	dw_eh_ptr_t record = lsda->type_table -
+		dwarf_size_of_fixed_size_field(lsda->type_table_encoding)*filter;
+	dw_eh_ptr_t start = record;
+	int64_t offset = read_value(lsda->type_table_encoding, &record);
+
+	if (0 == offset) { return Nil; }
+
+	// ...so we need to resolve it
+	char *class_name = (char*)(intptr_t)resolve_indirect_value(context,
+			lsda->type_table_encoding, offset, start);
+
+	if (0 == class_name) { return Nil; }
+
+	fprintf(stderr, "Class name: %s\n", class_name);
+
+	if (strcmp("@id", class_name) == 0) { return (Class)1; }
+
+	return (Class)objc_getClass(class_name);
+}
+
+static BOOL isKindOfClass(Class thrown, Class type)
+{
+	do
+	{
+		if (thrown == type)
+		{
+			return YES;
+		}
+		thrown = class_getSuperclass(thrown);
+	} while (Nil != thrown);
+
+	return NO;
+}
+
+
+static handler_type check_action_record(struct _Unwind_Context *context,
+                                        BOOL foreignException,
+                                        struct dwarf_eh_lsda *lsda,
+                                        dw_eh_ptr_t action_record,
+                                        Class thrown_class,
+                                        unsigned long *selector)
+{
+	//if (!action_record) { return handler_cleanup; }
+	while (action_record)
+	{
+		int filter = read_sleb128(&action_record);
+		dw_eh_ptr_t action_record_offset_base = action_record;
+		int displacement = read_sleb128(&action_record);
+		*selector = filter;
+		fprintf(stderr, "Filter: %d\n", filter);
+		if (filter > 0)
+		{
+			Class type = get_type_table_entry(context, lsda, filter);
+			fprintf(stderr, "%p type: %d\n", type, !foreignException);
+			// Catchall
+			if (Nil == type)
+			{
+				return handler_catchall;
+			}
+			// We treat id catches as catchalls when an object is thrown and as
+			// nothing when a foreign exception is thrown
+			else if ((Class)1 == type)
+			{
+				fprintf(stderr, "Found id catch\n");
+				if (!foreignException)
+				{
+					return handler_catchall_id;
+				}
+			}
+			else if (!foreignException && isKindOfClass(thrown_class, type))
+			{
+				fprintf(stderr, "found handler for %s\n", type->name);
+				return handler_class;
+			}
+			else if (thrown_class == type)
+			{
+				return handler_class;
+			}
+		}
+		else if (filter == 0)
+		{
+			fprintf(stderr, "0 filter\n");
+			// Cleanup?  I think the GNU ABI doesn't actually use this, but it
+			// would be a good way of indicating a non-id catchall...
+			return handler_cleanup;
+		}
+		else
+		{
+			fprintf(stderr, "Filter value: %d\n"
+					"Your compiler and I disagree on the correct layout of EH data.\n", 
+					filter);
+			abort();
+		}
+		*selector = 0;
+		action_record = displacement ? 
+			action_record_offset_base + displacement : 0;
+	}
+	return handler_none;
+}
+
+/**
+ * The Objective-C exception personality function.  
+ */
+BEGIN_PERSONALITY_FUNCTION(__gnu_objc_personality_v0)
+	fprintf(stderr, "Personality function called\n");
+	
+	// This personality function is for version 1 of the ABI.  If you use it
+	// with a future version of the ABI, it won't know what to do, so it
+	// reports a fatal error and give up before it breaks anything.
+	if (1 != version)
+	{
+		return _URC_FATAL_PHASE1_ERROR;
+	}
+	struct objc_exception *ex = 0;
+#ifndef fprintf
+	char *cls = (char*)&exceptionClass;
+#endif
+	fprintf(stderr, "Class: %c%c%c%c%c%c%c%c\n", cls[7], cls[6], cls[5], cls[4], cls[3], cls[2], cls[1], cls[0]);
+
+	// Check if this is a foreign exception.  If it is a C++ exception, then we
+	// have to box it.  If it's something else, like a LanguageKit exception
+	// then we ignore it (for now)
+	BOOL foreignException = exceptionClass != objc_exception_class;
+	// Is this a C++ exception containing an Objective-C++ object?
+	BOOL objcxxException = NO;
+	// The object to return
+	void *object = NULL;
+
+#ifdef NO_OBJCXX
+	if (exceptionClass == cxx_exception_class)
+	{
+		id obj = objc_object_for_cxx_exception(exceptionObject);
+		if (obj != (id)-1)
+		{
+			object = obj;
+			fprintf(stderr, "ObjC++ object exception %p\n", object);
+			objcxxException = YES;
+			// This is a foreign exception, buy for the purposes of exception
+			// matching, we pretend that it isn't.
+			foreignException = NO;
+		}
+	}
+#endif
+
+	Class thrown_class = Nil;
+
+	if (objcxxException)
+	{
+		thrown_class = (object == 0) ? Nil : classForObject((id)object);
+	}
+	// If it's not a foreign exception, then we know the layout of the
+	// language-specific exception stuff.
+	else if (!foreignException)
+	{
+		ex = (struct objc_exception*) ((char*)exceptionObject - 
+				offsetof(struct objc_exception, unwindHeader));
+
+		thrown_class = classForObject(ex->object);
+	}
+	else if (_objc_class_for_boxing_foreign_exception)
+	{
+		thrown_class = _objc_class_for_boxing_foreign_exception(exceptionClass);
+		fprintf(stderr, "Foreign class: %p\n", thrown_class);
+	}
+	unsigned char *lsda_addr = (void*)_Unwind_GetLanguageSpecificData(context);
+	fprintf(stderr, "LSDA: %p\n", lsda_addr);
+
+	// No LSDA implies no landing pads - try the next frame
+	if (0 == lsda_addr) { return _URC_CONTINUE_UNWIND; }
+
+	// These two variables define how the exception will be handled.
+	struct dwarf_eh_action action = {0};
+	unsigned long selector = 0;
+	
+	if (actions & _UA_SEARCH_PHASE)
+	{
+		fprintf(stderr, "Search phase...\n");
+		struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr);
+		action = dwarf_eh_find_callsite(context, &lsda);
+		handler_type handler = check_action_record(context, foreignException,
+				&lsda, action.action_record, thrown_class, &selector);
+		// If there's no action record, we've only found a cleanup, so keep
+		// searching for something real
+		if (handler == handler_class ||
+		   ((handler == handler_catchall_id) && !foreignException) ||
+			(handler == handler_catchall))
+		{
+			saveLandingPad(context, exceptionObject, ex, selector, action.landing_pad);
+			fprintf(stderr, "Found handler! %d\n", handler);
+			return _URC_HANDLER_FOUND;
+		}
+		return _URC_CONTINUE_UNWIND;
+	}
+	fprintf(stderr, "Phase 2: Fight!\n");
+
+	// TODO: If this is a C++ exception, we can cache the lookup and cheat a
+	// bit
+	if (!(actions & _UA_HANDLER_FRAME))
+	{
+		struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr);
+		action = dwarf_eh_find_callsite(context, &lsda);
+		// If there's no cleanup here, continue unwinding.
+		if (0 == action.landing_pad)
+		{
+			return _URC_CONTINUE_UNWIND;
+		}
+		handler_type handler = check_action_record(context, foreignException,
+				&lsda, action.action_record, thrown_class, &selector);
+		fprintf(stderr, "handler! %d %d\n", (int)handler,  (int)selector);
+		// If this is not a cleanup, ignore it and keep unwinding.
+		//if (check_action_record(context, foreignException, &lsda,
+				//action.action_record, thrown_class, &selector) != handler_cleanup)
+		if (handler != handler_cleanup)
+		{
+			fprintf(stderr, "Ignoring handler! %d\n",handler);
+			return _URC_CONTINUE_UNWIND;
+		}
+		fprintf(stderr, "Installing cleanup...\n");
+		// If there is a cleanup, we need to return the exception structure
+		// (not the object) to the calling frame.  The exception object
+		object = exceptionObject;
+		//selector = 0;
+	}
+	else if (foreignException || objcxxException)
+	{
+		struct dwarf_eh_lsda lsda = parse_lsda(context, lsda_addr);
+		action = dwarf_eh_find_callsite(context, &lsda);
+		check_action_record(context, foreignException, &lsda,
+				action.action_record, thrown_class, &selector);
+		// If it's a foreign exception, then box it.  If it's an Objective-C++
+		// exception, then we need to delete the exception object.
+		if (foreignException)
+		{
+			fprintf(stderr, "Doing the foreign exception thing...\n");
+			//[thrown_class exceptionWithForeignException: exceptionObject];
+			SEL box_sel = sel_registerName("exceptionWithForeignException:");
+			IMP boxfunction = objc_msg_lookup((id)thrown_class, box_sel);
+			object = boxfunction((id)thrown_class, box_sel, exceptionObject);
+			fprintf(stderr, "Boxed as %p\n", object);
+		}
+		else // ObjCXX exception
+		{
+			_Unwind_DeleteException(exceptionObject);
+		}
+	}
+	else
+	{
+		// Restore the saved info if we saved some last time.
+		loadLandingPad(context, exceptionObject, ex, &selector, &action.landing_pad);
+		object = ex->object;
+		free(ex);
+	}
+
+	_Unwind_SetIP(context, (unsigned long)action.landing_pad);
+	_Unwind_SetGR(context, __builtin_eh_return_data_regno(0), 
+			(unsigned long)object);
+	_Unwind_SetGR(context, __builtin_eh_return_data_regno(1), selector);
+
+	return _URC_INSTALL_CONTEXT;
+}
+
+// FIXME!
+#ifndef __arm__
+BEGIN_PERSONALITY_FUNCTION(__gnustep_objcxx_personality_v0)
+	if (exceptionClass == objc_exception_class)
+	{
+		struct objc_exception *ex = (struct objc_exception*)
+			((char*)exceptionObject - offsetof(struct objc_exception,
+				unwindHeader));
+		if (0 == ex->cxx_exception)
+		{
+			id *newEx = __cxa_allocate_exception(sizeof(id));
+			*newEx = ex->object;
+			ex->cxx_exception = objc_init_cxx_exception(newEx);
+			ex->cxx_exception->exception_class = cxx_exception_class;
+			ex->cxx_exception->exception_cleanup = cleanup;
+			ex->cxx_exception->private_1 = exceptionObject->private_1;
+			ex->cxx_exception->private_2 = exceptionObject->private_2;
+		}
+		exceptionObject = ex->cxx_exception;
+		exceptionClass = cxx_exception_class;
+	}
+	return CALL_PERSONALITY_FUNCTION(__gxx_personality_v0);
+}
+#endif
diff --git a/third_party/libobjc/encoding2.c b/third_party/libobjc/encoding2.c
new file mode 100644
index 0000000000000000000000000000000000000000..5c9b4edcf1a5380a6c73838f9274845ae60c90a1
--- /dev/null
+++ b/third_party/libobjc/encoding2.c
@@ -0,0 +1,605 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "objc/runtime.h"
+#include "method_list.h"
+#include "visibility.h"
+
+size_t objc_alignof_type (const char *type);
+
+// It would be so nice if this works, but in fact it returns nonsense:
+//#define alignof(x) __alignof__(x)
+//
+#define alignof(type) __builtin_offsetof(struct { const char c; type member; }, member)
+
+const char *objc_skip_type_qualifiers (const char *type)
+{
+	static const char *type_qualifiers = "rnNoORV";
+	while('\0' != *type && strchr(type_qualifiers, *type))
+	{
+		type++;
+	}
+	return type;
+}
+
+static const char *sizeof_type(const char *type, size_t *size);
+
+const char *objc_skip_typespec(const char *type)
+{
+	size_t ignored = 0;
+	return sizeof_type(type, &ignored);
+}
+
+const char *objc_skip_argspec(const char *type)
+{
+	type = objc_skip_typespec(type);
+	while(isdigit(*type)) { type++; }
+	return type;
+}
+
+PRIVATE size_t lengthOfTypeEncoding(const char *types)
+{
+	if ((NULL == types) || ('\0' == types[0])) { return 0; }
+	const char *end = objc_skip_typespec(types);
+	size_t length = end - types;
+	return length;
+}
+
+static char* copyTypeEncoding(const char *types)
+{
+	size_t length = lengthOfTypeEncoding(types);
+	char *copy = malloc(length + 1);
+	memcpy(copy, types, length);
+	copy[length] = '\0';
+	return copy;
+}
+
+static const char * findParameterStart(const char *types, unsigned int index)
+{
+	for (unsigned int i=0 ; i<index ; i++)
+	{
+		types = objc_skip_argspec(types);
+		if ('\0' == *types)
+		{
+			return NULL;
+		}
+	}
+	return types;
+}
+
+
+typedef const char *(*type_parser)(const char*, void*);
+
+static int parse_array(const char **type, type_parser callback, void *context)
+{
+	// skip [
+	(*type)++;
+	int element_count = (int)strtol(*type, (char**)type, 10);
+	*type = callback(*type, context);
+	// skip ]
+	(*type)++;
+	return element_count;
+}
+
+static void parse_struct_or_union(const char **type, type_parser callback, void *context, char endchar)
+{
+	// Skip the ( and structure name
+	do
+	{
+		(*type)++;
+		// Opaque type has no =definition
+		if (endchar == **type) { (*type)++; return; }
+	} while('=' != **type);
+	// Skip =
+	(*type)++;
+
+	while (**type != endchar)
+	{
+		// Structure elements sometimes have their names in front of each
+		// element, as in {NSPoint="x"f"y"f} - We need to skip the type name
+		// here.
+		//
+		// TODO: In a future version we should provide a callback that lets
+		// users of this code get the field name
+		if ('"'== **type)
+		{
+
+			do
+			{
+				(*type)++;
+			} while ('"' != **type);
+			// Skip the closing "
+			(*type)++;
+		}
+		*type = callback(*type, context);
+	}
+	// skip }
+	(*type)++;
+}
+
+static void parse_union(const char **type, type_parser callback, void *context)
+{
+	parse_struct_or_union(type, callback, context, ')');
+}
+
+static void parse_struct(const char **type, type_parser callback, void *context)
+{
+	parse_struct_or_union(type, callback, context, '}');
+}
+
+inline static void round_up(size_t *v, size_t b)
+{
+	if (0 == b)
+	{
+		return;
+	}
+
+	if (*v % b)
+	{
+		*v += b - (*v % b);
+	}
+}
+inline static size_t max(size_t v, size_t v2)
+{
+	return v>v2 ? v : v2;
+}
+
+static const char *sizeof_union_field(const char *type, size_t *size);
+
+static const char *sizeof_type(const char *type, size_t *size)
+{
+	type = objc_skip_type_qualifiers(type);
+	switch (*type)
+	{
+		// For all primitive types, we round up the current size to the
+		// required alignment of the type, then add the size
+#define APPLY_TYPE(typeName, name, capitalizedName, encodingChar) \
+		case encodingChar:\
+		{\
+			round_up(size, (alignof(typeName) * 8));\
+			*size += (sizeof(typeName) * 8);\
+			return type + 1;\
+		}
+#define SKIP_ID 1
+#define NON_INTEGER_TYPES 1
+#include "type_encoding_cases.h"
+		case '@':
+		{
+			round_up(size, (alignof(id) * 8));
+			*size += (sizeof(id) * 8);
+			if (*(type+1) == '?')
+			{
+				type++;
+			}
+			return type + 1;
+		}
+		case '?':
+		case 'v': return type+1;
+		case 'j':
+		{
+			type++;
+			switch (*type)
+			{
+#define APPLY_TYPE(typeName, name, capitalizedName, encodingChar) \
+		case encodingChar:\
+		{\
+			round_up(size, (alignof(_Complex typeName) * 8));\
+			*size += (sizeof(_Complex typeName) * 8);\
+			return type + 1;\
+		}
+#include "type_encoding_cases.h"
+			}
+		}
+		case '{':
+		{
+			const char *t = type;
+			parse_struct(&t, (type_parser)sizeof_type, size);
+			size_t align = objc_alignof_type(type);
+			round_up(size, align * 8);
+			return t;
+		}
+		case '[':
+		{
+			const char *t = type;
+			size_t element_size = 0;
+			// FIXME: aligned size
+			int element_count = parse_array(&t, (type_parser)sizeof_type, &element_size);
+			(*size) += element_size * element_count;
+			return t;
+		}
+		case '(':
+		{
+			const char *t = type;
+			size_t union_size = 0;
+			parse_union(&t, (type_parser)sizeof_union_field, &union_size);
+			*size += union_size;
+			return t;
+		}
+		case 'b':
+		{
+			// Consume the b
+			type++;
+			// Ignore the offset
+			strtol(type, (char**)&type, 10);
+			// Consume the element type
+			type++;
+			// Read the number of bits
+			*size += strtol(type, (char**)&type, 10);
+			return type;
+		}
+		case '^':
+		{
+			// All pointers look the same to me.
+			*size += sizeof(void*) * 8;
+			size_t ignored;
+			// Skip the definition of the pointeee type.
+			return sizeof_type(type+1, &ignored);
+		}
+	}
+	abort();
+	return NULL;
+}
+
+static const char *sizeof_union_field(const char *type, size_t *size)
+{
+	size_t field_size = 0;
+	const char *end = sizeof_type(type, &field_size);
+	*size = max(*size, field_size);
+	return end;
+}
+
+static const char *alignof_type(const char *type, size_t *align)
+{
+	type = objc_skip_type_qualifiers(type);
+	switch (*type)
+	{
+		// For all primitive types, we return the maximum of the new alignment
+		// and the old one
+#define APPLY_TYPE(typeName, name, capitalizedName, encodingChar) \
+		case encodingChar:\
+		{\
+			*align = max((alignof(typeName) * 8), *align);\
+			return type + 1;\
+		}
+#define NON_INTEGER_TYPES 1
+#define SKIP_ID 1
+#include "type_encoding_cases.h"
+		case '@':
+		{
+			*align = max((alignof(id) * 8), *align);\
+			if (*(type+1) == '?')
+			{
+				type++;
+			}
+			return type + 1;
+		}
+		case '?':
+		case 'v': return type+1;
+		case 'j':
+		{
+			type++;
+			switch (*type)
+			{
+#define APPLY_TYPE(typeName, name, capitalizedName, encodingChar) \
+		case encodingChar:\
+		{\
+			*align = max((alignof(_Complex typeName) * 8), *align);\
+			return type + 1;\
+		}
+#include "type_encoding_cases.h"
+			}
+		}
+		case '{':
+		{
+			const char *t = type;
+			parse_struct(&t, (type_parser)alignof_type, align);
+			return t;
+		}
+		case '(':
+		{
+			const char *t = type;
+			parse_union(&t, (type_parser)alignof_type, align);
+			return t;
+		}
+		case '[':
+		{
+			const char *t = type;
+			parse_array(&t, (type_parser)alignof_type, &align);
+			return t;
+		}
+		case 'b':
+		{
+			// Consume the b
+			type++;
+			// Ignore the offset
+			strtol(type, (char**)&type, 10);
+			// Alignment of a bitfield is the alignment of the type that
+			// contains it
+			type = alignof_type(type, align);
+			// Ignore the number of bits
+			strtol(type, (char**)&type, 10);
+			return type;
+		}
+		case '^':
+		{
+			*align = max((alignof(void*) * 8), *align);
+			// All pointers look the same to me.
+			size_t ignored;
+			// Skip the definition of the pointeee type.
+			return alignof_type(type+1, &ignored);
+		}
+	}
+	abort();
+	return NULL;
+}
+
+size_t objc_sizeof_type(const char *type)
+{
+	size_t size = 0;
+	sizeof_type(type, &size);
+	return size / 8;
+}
+
+size_t objc_alignof_type (const char *type)
+{
+	size_t align = 0;
+	alignof_type(type, &align);
+	return align / 8;
+}
+
+size_t objc_aligned_size(const char *type)
+{
+	size_t size  = objc_sizeof_type(type);
+	size_t align = objc_alignof_type(type);
+	return size + (size % align);
+}
+
+size_t objc_promoted_size(const char *type)
+{
+	size_t size = objc_sizeof_type(type);
+	return size + (size % sizeof(void*));
+}
+
+void method_getReturnType(Method method, char *dst, size_t dst_len)
+{
+	if (NULL == method) { return; }
+	//TODO: Coped and pasted code.  Factor it out.
+	const char *types = method->types;
+	size_t length = lengthOfTypeEncoding(types);
+	if (length < dst_len)
+	{
+		memcpy(dst, types, length);
+		dst[length] = '\0';
+	}
+	else
+	{
+		memcpy(dst, types, dst_len);
+	}
+}
+
+const char *method_getTypeEncoding(Method method)
+{
+	if (NULL == method) { return NULL; }
+	return method->types;
+}
+
+
+void method_getArgumentType(Method method,
+                            unsigned int index,
+                            char *dst,
+                            size_t dst_len)
+{
+	if (NULL == method) { return; }
+	const char *types = findParameterStart(method->types, index);
+	if (NULL == types)
+	{
+		strncpy(dst, "", dst_len);
+		return;
+	}
+	size_t length = lengthOfTypeEncoding(types);
+	if (length < dst_len)
+	{
+		memcpy(dst, types, length);
+		dst[length] = '\0';
+	}
+	else
+	{
+		memcpy(dst, types, dst_len);
+	}
+}
+
+unsigned method_getNumberOfArguments(Method method)
+{
+	if (NULL == method) { return 0; }
+	const char *types = method->types;
+	unsigned int count = 0;
+	while('\0' != *types)
+	{
+		types = objc_skip_argspec(types);
+		count++;
+	}
+	return count - 1;
+}
+
+unsigned method_get_number_of_arguments(struct objc_method *method)
+{
+	return method_getNumberOfArguments(method);
+}
+
+
+char* method_copyArgumentType(Method method, unsigned int index)
+{
+	if (NULL == method) { return NULL; }
+	const char *types = findParameterStart(method->types, index);
+	if (NULL == types)
+	{
+		return NULL;
+	}
+	return copyTypeEncoding(types);
+}
+
+char* method_copyReturnType(Method method)
+{
+	if (NULL == method) { return NULL; }
+	return copyTypeEncoding(method->types);
+}
+
+unsigned objc_get_type_qualifiers (const char *type)
+{
+	unsigned flags = 0;
+#define MAP(chr, bit) case chr: flags |= (1<<bit); break;
+	do
+	{
+		switch (*(type++))
+		{
+			default: return flags;
+			MAP('r', 1)
+			MAP('n', 1)
+			MAP('o', 2)
+			MAP('N', 3)
+			MAP('O', 4)
+			MAP('V', 10)
+			MAP('R', 8)
+		}
+	} while (1);
+}
+
+struct objc_struct_layout
+{
+	const char *original_type;
+	const char *type;
+	const char *prev_type;
+	unsigned int record_size;
+	unsigned int record_align;
+};
+
+// Note: The implementations of these functions is horrible.
+void objc_layout_structure (const char *type,
+                            struct objc_struct_layout *layout)
+{
+	layout->original_type = type;
+	layout->type = 0;
+}
+
+static const char *layout_structure_callback(const char *type, struct objc_struct_layout *layout)
+{
+	size_t align = 0;
+	size_t size = 0;
+	const char *end = sizeof_type(type, &size);
+	alignof_type(type, &align);
+	//printf("Callback called with %s\n", type);
+	if (layout->prev_type < type)
+	{
+		if (layout->record_align == 0)
+		{
+			layout->record_align = align;
+			layout->type = type;
+		}
+	}
+	else
+	{
+		size_t rsize = (size_t)layout->record_size;
+		round_up(&rsize, align);
+		layout->record_size = rsize + size;
+	}
+	return end;
+}
+
+BOOL objc_layout_structure_next_member(struct objc_struct_layout *layout)
+{
+	const char *end = layout->type;
+	layout->record_size = 0;
+	layout->record_align = 0;
+	layout->prev_type = layout->type;
+	const char *type = layout->original_type;
+	parse_struct(&type, (type_parser)layout_structure_callback, layout);
+	//printf("Calculated: (%s) %s %d %d\n", layout->original_type, layout->type, layout->record_size, layout->record_align);
+	//printf("old start %s, new start %s\n", end, layout->type);
+	return layout->type != end;
+}
+
+void objc_layout_structure_get_info (struct objc_struct_layout *layout,
+                                     unsigned int *offset,
+                                     unsigned int *align,
+                                     const char **type)
+{
+	//printf("%p\n", layout);
+	*type = layout->type;
+	size_t off = layout->record_size / 8;
+	*align= layout->record_align / 8;
+	round_up(&off, (size_t)*align);
+	*offset = (unsigned int)off;
+}
+
+#ifdef ENCODING_TESTS
+
+#define TEST(type) do {\
+	if (alignof(type) != objc_alignof_type(@encode(type)))\
+		printf("Incorrect alignment for %s: %d != %d\n", @encode(type), objc_alignof_type(@encode(type)), alignof(type));\
+	if (sizeof(type) != objc_sizeof_type(@encode(type)))\
+		printf("Incorrect size for %s: %d != %d\n", @encode(type), objc_sizeof_type(@encode(type)), sizeof(type));\
+	} while(0)
+
+struct foo
+{
+	int a[2];
+	int b:5;
+	struct
+	{
+		double d;
+		const char *str;
+		float e;
+	}c;
+	long long **g;
+	union { const char c; long long b; } h;
+	long long f;
+	_Complex int z;
+	_Complex double y;
+	char v;
+};
+
+typedef struct
+{
+	float x,y;
+} Point;
+
+typedef struct
+{
+	Point a, b;
+} Rect;
+
+
+int main(void)
+{
+	TEST(int);
+	TEST(const char);
+	TEST(unsigned long long);
+	TEST(_Complex int);
+	TEST(struct foo);
+	struct objc_struct_layout layout;
+
+	objc_layout_structure(@encode(Rect), &layout);
+	while (objc_layout_structure_next_member (&layout))
+	{
+		unsigned offset;
+		unsigned align;
+		const char *ftype;
+		struct objc_struct_layout layout2;
+		objc_layout_structure_get_info (&layout, &offset, &align, &ftype);
+		printf("%s: offset: %d, alignment: %d\n", ftype, offset, align);
+		objc_layout_structure(ftype, &layout2);
+		while (objc_layout_structure_next_member (&layout2))
+		{
+			objc_layout_structure_get_info (&layout2, &offset, &align, &ftype);
+			printf("%s: offset: %d, alignment: %d\n", ftype, offset, align);
+		}
+	}
+	printf("%d\n", offsetof(Rect, a.x));
+	printf("%d\n", offsetof(Rect, a.y));
+	printf("%d\n", offsetof(Rect, b.x));
+	printf("%d\n", offsetof(Rect, b.y));
+
+}
+#endif
diff --git a/third_party/libobjc/gc_boehm.c b/third_party/libobjc/gc_boehm.c
new file mode 100644
index 0000000000000000000000000000000000000000..e0b0a110f7f5f1620418c179ca3fd20ca2945c48
--- /dev/null
+++ b/third_party/libobjc/gc_boehm.c
@@ -0,0 +1,733 @@
+#define GNUSTEP_LIBOBJC_NO_LEGACY
+#include "objc/runtime.h"
+#include "objc/toydispatch.h"
+#include "class.h"
+#include "ivar.h"
+#include "lock.h"
+#include "objc/objc-auto.h"
+#include "visibility.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <signal.h>
+#include "gc_ops.h"
+#define I_HIDE_POINTERS
+
+
+/**
+ * Dispatch queue used to invoke finalizers.
+ */
+static dispatch_queue_t finalizer_queue;
+/**
+ * Should finalizers be invoked in their own thread?
+ */
+static BOOL finalizeThreaded;
+/**
+ * Should we do some (not 100% reliable) buffer overflow checking.
+ */
+static size_t canarySize;
+/**
+ * The canary value.  Used to check for overruns.  When an allocation is
+ * finalized, we check whether it ends with this value.
+ */
+static uint32_t canary;
+/**
+ * Destination to write allocation log to.  This can be used to implement the
+ * equivalent of malloc_history
+ */
+static FILE *allocationLog;
+
+struct objc_slot* objc_get_slot(Class cls, SEL selector);
+
+/*
+ * Citing boehm-gc's README.linux:
+ *
+ * 3a) Every file that makes thread calls should define GC_LINUX_THREADS and
+ *  _REENTRANT and then include gc.h.  Gc.h redefines some of the
+ *  pthread primitives as macros which also provide the collector with
+ *  information it requires.
+ */
+#ifdef __linux__
+#	define GC_LINUX_THREADS
+
+#	ifndef _REENTRANT
+#		define _REENTRANT
+#	endif
+
+#endif
+#include <gc/gc.h>
+#include <gc/gc_typed.h>
+
+#ifndef __has_builtin
+#	define __has_builtin(x) 0
+#endif
+#if !__has_builtin(__sync_swap)
+#define __sync_swap __sync_lock_test_and_set
+#endif
+
+void call_cxx_destruct(id obj);
+
+#ifdef NO_EXECINFO
+static inline void dump_stack(char *msg, void *addr) {}
+#else 
+#include <execinfo.h>
+static inline void dump_stack(char *msg, void *addr)
+{
+	if (NULL == allocationLog) { return; }
+	void *array[30];
+	int frames = backtrace(array, 30);
+	fprintf(allocationLog, "%s %p\n", msg, addr);
+	fflush(allocationLog);
+	backtrace_symbols_fd(array, frames, fileno(allocationLog));
+	fflush(allocationLog);
+}
+#endif
+
+Class dead_class;
+
+Class objc_lookup_class(const char*);
+
+GC_descr gc_typeForClass(Class cls);
+void gc_setTypeForClass(Class cls, GC_descr type);
+
+static unsigned long collectionType(unsigned options)
+{
+	// Low 2 bits in GC options are used for the
+	return options & 3;
+}
+
+static size_t CollectRatio     = 0x10000;
+static size_t CollectThreshold = 0x10000;
+
+void objc_set_collection_threshold(size_t threshold)
+{
+	CollectThreshold = threshold;
+}
+void objc_set_collection_ratio(size_t ratio)
+{
+	CollectRatio = ratio;
+}
+
+void objc_collect(unsigned long options)
+{
+	size_t newAllocations = GC_get_bytes_since_gc();
+	// Skip collection if we haven't allocated much memory and this is a
+	// collect if needed collection
+	if ((options & OBJC_COLLECT_IF_NEEDED) && (newAllocations < CollectThreshold))
+	{
+		return;
+	}
+	switch (collectionType(options))
+	{
+		case OBJC_RATIO_COLLECTION:
+			if (newAllocations >= CollectRatio)
+			{
+				GC_gcollect();
+			}
+			else
+			{
+				GC_collect_a_little();
+			}
+			break;
+		case OBJC_GENERATIONAL_COLLECTION:
+			GC_collect_a_little();
+			break;
+		case OBJC_FULL_COLLECTION:
+			GC_gcollect();
+			break;
+		case OBJC_EXHAUSTIVE_COLLECTION:
+		{
+			size_t freeBytes = 0;
+			while (GC_get_free_bytes() != freeBytes)
+			{
+				freeBytes = GC_get_free_bytes();
+				GC_gcollect();
+			}
+		}
+	}
+}
+
+BOOL objc_collectingEnabled(void)
+{
+	return GC_dont_gc == 0;
+}
+
+void objc_gc_disable(void)
+{
+	GC_disable();
+}
+void objc_gc_enable(void)
+{
+	GC_enable();
+}
+void* objc_gc_collectable_address(void* ptr)
+{
+	return GC_base(ptr);
+}
+
+BOOL objc_atomicCompareAndSwapPtr(id predicate, id replacement, volatile id *objectLocation)
+{
+	return __sync_bool_compare_and_swap(objectLocation, predicate, replacement);
+}
+BOOL objc_atomicCompareAndSwapPtrBarrier(id predicate, id replacement, volatile id *objectLocation)
+{
+	return __sync_bool_compare_and_swap(objectLocation, predicate, replacement);
+}
+
+BOOL objc_atomicCompareAndSwapGlobal(id predicate, id replacement, volatile id *objectLocation)
+{
+	return objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation);
+}
+BOOL objc_atomicCompareAndSwapGlobalBarrier(id predicate, id replacement, volatile id *objectLocation)
+{
+	return objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation);
+}
+BOOL objc_atomicCompareAndSwapInstanceVariable(id predicate, id replacement, volatile id *objectLocation)
+{
+	return objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation);
+}
+BOOL objc_atomicCompareAndSwapInstanceVariableBarrier(id predicate, id replacement, volatile id *objectLocation)
+{
+	return objc_atomicCompareAndSwapPtr(predicate, replacement, objectLocation);
+}
+
+id objc_assign_strongCast(id val, id *ptr)
+{
+	*ptr = val;
+	return val;
+}
+
+id objc_assign_global(id val, id *ptr)
+{
+	if (isGCEnabled)
+	{
+		GC_add_roots(ptr, ptr+1);
+	}
+	*ptr = val;
+	return val;
+}
+
+id objc_assign_ivar(id val, id dest, ptrdiff_t offset)
+{
+	*(id*)((char*)dest+offset) = val;
+	return val;
+}
+
+struct memmove_args
+{
+	void *dst;
+	const void *src;
+	size_t size;
+};
+
+static void* callMemmove(void *args)
+{
+	struct memmove_args *a = args;
+	memmove(a->dst, a->src, a->size);
+	return a->dst;
+}
+
+void *objc_memmove_collectable(void *dst, const void *src, size_t size)
+{
+	// For small copies, we copy onto the stack then copy from the stack.  This
+	// ensures that pointers are always present in a scanned region.  For
+	// larger copies, we just lock the GC to prevent it from freeing the memory
+	// while the system memmove() does the real copy.  The first case avoids
+	// the need to acquire the lock, but will perform worse for very large
+	// copies since we are copying the data twice (and because stack space is
+	// relatively scarce).
+	if (size < 128)
+	{
+		char buffer[128];
+		memcpy(buffer, src, size);
+		__sync_synchronize();
+		memcpy(dst, buffer, size);
+		// In theory, we should zero the on-stack buffer here to prevent the GC
+		// from seeing spurious pointers, but it's not really important because
+		// the contents of the buffer is duplicated on the heap and overwriting
+		// it will typically involve another copy to this function.  This will
+		// not be the case if we are storing in a dead object, but that's
+		// probably sufficiently infrequent that we shouldn't worry about
+		// optimising for that case.
+		return dst;
+	}
+	struct memmove_args args = {dst, src, size};
+	return GC_call_with_alloc_lock(callMemmove, &args);
+}
+/**
+ * Weak Pointers:
+ *
+ * To implement weak pointers, we store the hidden pointer (bits all flipped)
+ * in the real address.  We tell the GC to zero the pointer when the associated
+ * object is finalized.  The read barrier locks the GC to prevent it from
+ * freeing anything, deobfuscates the pointer (at which point it becomes a
+ * GC-visible on-stack pointer), and then returns it.
+ */
+
+static void *readWeakLocked(void *ptr)
+{
+	void *val = *(void**)ptr;
+	return 0 == val ? val : REVEAL_POINTER(val);
+}
+
+id objc_read_weak(id *location)
+{
+	if (!isGCEnabled)
+	{
+		return *location;
+	}
+	return GC_call_with_alloc_lock(readWeakLocked, location);
+}
+
+id objc_assign_weak(id value, id *location)
+{
+	if (!isGCEnabled)
+	{
+		*location = value;
+		return value;
+	}
+	// Temporarily zero this pointer and get the old value
+	id old = __sync_swap(location, 0);
+	if (0 != old)
+	{
+		GC_unregister_disappearing_link((void**)location);
+	}
+	// If the value is not GC'd memory (e.g. a class), the collector will crash
+	// trying to collect it when you add it as the target of a disappearing
+	// link.
+	if (0 != GC_base(value))
+	{
+		GC_GENERAL_REGISTER_DISAPPEARING_LINK((void**)location, value);
+	}
+	// If some other thread has modified this, then we may have two different
+	// objects registered to make this pointer 0 if either is destroyed.  This
+	// would be bad, so we need to make sure that we unregister them and
+	// register the correct one.
+	if (!__sync_bool_compare_and_swap(location, old, (id)HIDE_POINTER(value)))
+	{
+		return objc_assign_weak(value, location);
+	}
+	return value;
+}
+
+static SEL finalize;
+Class zombie_class;
+
+
+static void runFinalize(void *addr, void *context)
+{
+	dump_stack("Freeing Object: ", addr);
+	id obj = addr;
+	size_t size = (uintptr_t)context;
+	if ((canarySize > 0) &&
+		(*(uint32_t*)((char*)obj + size) != canary))
+	{
+		fprintf(stderr, "Something wrote past the end of %p\n", addr);
+		if (obj->isa != Nil)
+		{
+			fprintf(stderr, "Instance of %s\n", obj->isa->name);
+		}
+		abort();
+	}
+	//fprintf(stderr, "FINALIZING %p (%s)\n", addr, ((id)addr)->isa->name);
+	if (Nil == obj->isa) { return; }
+	struct objc_slot *slot = objc_get_slot(obj->isa, finalize);
+	if (NULL != slot)
+	{
+		slot->method(obj, finalize);
+	}
+	call_cxx_destruct(obj);
+	*(void**)addr = zombie_class;
+}
+
+static void collectIvarForClass(Class cls, GC_word *bitmap)
+{
+	for (unsigned i=0 ; (cls->ivars != 0) && (i<cls->ivars->count) ; i++)
+	{
+		struct objc_ivar *ivar = &cls->ivars->ivar_list[i];
+		size_t start = ivar->offset;
+		size_t end = i+1 < cls->ivars->count ? cls->ivars->ivar_list[i+1].offset
+		                                     : cls->instance_size;
+		switch (ivar->type[0])
+		{
+			case '[': case '{': case '(':
+				// If the structure / array / union type doesn't contain any
+				// pointers, then skip it.  We still need to be careful of packed
+				if ((strchr(ivar->type, '^') == 0) &&
+				    (strchr(ivar->type, '@') == 0))
+				{
+					break;
+				}
+			// Explicit pointer types
+			case '^': case '@':
+				for (unsigned b=(start / sizeof(void*)) ; b<(end/sizeof(void*)) ; b++)
+				{
+					GC_set_bit(bitmap, b);
+				}
+		}
+	}
+	if (cls->super_class)
+	{
+		collectIvarForClass(cls->super_class, bitmap);
+	}
+}
+
+static GC_descr descriptor_for_class(Class cls)
+{
+	GC_descr descr = gc_typeForClass(cls);
+
+	if (0 != descr) { return descr; }
+
+	LOCK_RUNTIME_FOR_SCOPE();
+
+	descr = (GC_descr)gc_typeForClass(cls);
+	if (0 != descr) { return descr; }
+
+	size_t size = cls->instance_size / 8 + 1;
+	GC_word bitmap[size];
+	memset(bitmap, 0, size);
+	collectIvarForClass(cls, bitmap);
+	// It's safe to round down here - if a class ends with an ivar that is
+	// smaller than a pointer, then it can't possibly be a pointer.
+	//fprintf(stderr, "Class is %d byes, %d words\n", cls->instance_size, cls->instance_size/sizeof(void*));
+	descr = GC_make_descriptor(bitmap, cls->instance_size / sizeof(void*));
+	gc_setTypeForClass(cls, descr);
+	return descr;
+}
+
+static id allocate_class(Class cls, size_t extra)
+{
+	size_t size = class_getInstanceSize(cls);
+	if (canarySize)
+	{
+		extra += 4;
+	}
+	id obj = 0;
+	// If there are some extra bytes, they may contain pointers, so we ignore
+	// the type
+	if (extra > 0)
+	{
+		size += extra;
+		// FIXME: Overflow checking!
+		obj = GC_MALLOC(size);
+	}
+	else
+	{
+		obj = GC_MALLOC_EXPLICITLY_TYPED(size, descriptor_for_class(cls));
+	}
+	//fprintf(stderr, "Allocating %p (%s + %d).  Base is %p\n", obj, cls->name, extra, GC_base(obj));
+	// It would be nice not to register a finaliser if the object didn't
+	// implement finalize or .cxx_destruct methods.  Unfortunately, this is not
+	// possible, because a class may add a finalize method as it runs.
+	GC_REGISTER_FINALIZER_NO_ORDER(obj, runFinalize,
+			(void*)(uintptr_t)size-canarySize, 0, 0);
+	if (canarySize > 0)
+	{
+		*(uint32_t*)((char*)obj + size - canarySize) = canary;
+	}
+	dump_stack("Allocating object", obj);
+	return obj;
+}
+
+static void free_object(id obj) {}
+id objc_allocate_object(Class cls, int extra)
+{
+	return class_createInstance(cls, extra);
+}
+
+static void registerThread(BOOL errorOnNotRegistered)
+{
+	struct GC_stack_base base;
+	if (GC_get_stack_base(&base) != GC_SUCCESS)
+	{
+		fprintf(stderr, "Unable to find stack base for new thread\n");
+		abort();
+	}
+	switch (GC_register_my_thread(&base))
+	{
+		case GC_SUCCESS:
+			if (errorOnNotRegistered)
+			{
+				fprintf(stderr, "Thread should have already been registered with the GC\n");
+			}
+		case GC_DUPLICATE:
+			return;
+		case GC_NO_THREADS:
+		case GC_UNIMPLEMENTED:
+			fprintf(stderr, "Unable to register stack\n");
+			abort();
+	}
+}
+
+void objc_registerThreadWithCollector(void)
+{
+	registerThread(NO);
+}
+void objc_unregisterThreadWithCollector(void)
+{
+	GC_unregister_my_thread();
+}
+void objc_assertRegisteredThreadWithCollector()
+{
+	registerThread(YES);
+}
+
+/**
+ * Structure stored for each GC
+ */
+static struct gc_refcount
+{
+	/** Reference count */
+	intptr_t refCount;
+	/** Strong pointer */
+	id ptr;
+} null_refcount = {0};
+
+static int refcount_compare(const void *ptr, struct gc_refcount rc)
+{
+	return ptr == rc.ptr;
+}
+static uint32_t ptr_hash(const void *ptr)
+{
+	// Bit-rotate right 4, since the lowest few bits in an object pointer will
+	// always be 0, which is not so useful for a hash value
+	return ((uintptr_t)ptr >> 4) | ((uintptr_t)ptr << ((sizeof(id) * 8) - 4));
+}
+static uint32_t refcount_hash(struct gc_refcount rc)
+{
+	return ptr_hash(rc.ptr);
+}
+static int isEmpty(struct gc_refcount rc)
+{
+	return rc.ptr == NULL;
+}
+#define MAP_TABLE_VALUE_NULL isEmpty
+#define MAP_TABLE_NAME refcount
+#define MAP_TABLE_COMPARE_FUNCTION refcount_compare
+#define MAP_TABLE_HASH_KEY ptr_hash
+#define MAP_TABLE_HASH_VALUE refcount_hash
+#define MAP_TABLE_VALUE_TYPE struct gc_refcount
+#define MAP_TABLE_VALUE_PLACEHOLDER null_refcount
+#define MAP_TABLE_TYPES_BITMAP (1<<(offsetof(struct gc_refcount, ptr) / sizeof(void*)))
+#define MAP_TABLE_ACCESS_BY_REFERENCE
+#include "hash_table.h"
+
+static refcount_table *refcounts;
+
+id objc_gc_retain(id object)
+{
+	struct gc_refcount *refcount = refcount_table_get(refcounts, object);
+	if (NULL == refcount)
+	{
+		LOCK_FOR_SCOPE(&(refcounts->lock));
+		refcount = refcount_table_get(refcounts, object);
+		if (NULL == refcount)
+		{
+			struct gc_refcount rc = { 1, object};
+			refcount_insert(refcounts, rc);
+			return object;
+		}
+	}
+	__sync_fetch_and_add(&(refcount->refCount), 1);
+	return object;
+}
+void objc_gc_release(id object)
+{
+	struct gc_refcount *refcount = refcount_table_get(refcounts, object);
+	// This object has not been explicitly retained, don't release it
+	if (0 == refcount) { return; }
+
+	if (0 == __sync_sub_and_fetch(&(refcount->refCount), 1))
+	{
+		LOCK_FOR_SCOPE(&(refcounts->lock));
+		refcount->ptr = 0;
+		__sync_synchronize();
+		// If another thread has incremented the reference count while we were
+		// doing this, then we need to add the count back into the table,
+		// otherwise we can carry on.
+		if (!__sync_bool_compare_and_swap(&(refcount->refCount), 0, 0))
+		{
+			refcount->ptr = object;
+		}
+	}
+}
+int objc_gc_retain_count(id object)
+{
+	struct gc_refcount *refcount = refcount_table_get(refcounts, object);
+	return (0 == refcount) ? 0 : refcount->refCount;
+}
+
+
+static void nuke_buffer(void *addr, void *s)
+{
+	return;
+	dump_stack("Freeing allocation: ", addr);
+	uintptr_t size = (uintptr_t)s;
+	if (canary != *(uint32_t*)((char*)addr + size))
+	{
+		fprintf(stderr,
+		        "Something wrote past the end of memory allocation %p\n",
+		        addr);
+		abort();
+	}
+	memset(addr, 0, size);
+}
+
+void* objc_gc_allocate_collectable(size_t size, BOOL isScanned)
+{
+	void *buffer;
+	if (isScanned)
+	{
+		buffer = GC_MALLOC(size+canarySize);
+	}
+	else
+	{
+		buffer = GC_MALLOC_ATOMIC(size+canarySize);
+		memset(buffer, 0, size);
+	}
+	if (canarySize > 0)
+	{
+		*(uint32_t*)((char*)buffer + size) = canary;
+		GC_REGISTER_FINALIZER_NO_ORDER(buffer, nuke_buffer,
+				(void*)(uintptr_t)size, 0, 0);
+	}
+	dump_stack("Allocating memory", buffer);
+	return buffer;
+}
+void* objc_gc_reallocate_collectable(void *ptr, size_t size, BOOL isScanned)
+{
+	if (0 == size) { return 0; }
+	void *new = isScanned ? GC_MALLOC(size) : GC_MALLOC_ATOMIC(size);
+
+	if (0 == new) { return 0; }
+
+	if (NULL != ptr)
+	{
+		size_t oldSize = GC_size(ptr);
+		if (oldSize < size)
+		{
+			size = oldSize;
+		}
+		memcpy(new, ptr, size);
+	}
+	dump_stack("New allocation from realloc: ", new);
+	return new;
+}
+
+static void collectAndDumpStats(int signalNo)
+{
+	objc_collect(OBJC_EXHAUSTIVE_COLLECTION);
+	GC_dump();
+}
+
+static void deferredFinalizer(void)
+{
+	GC_invoke_finalizers();
+}
+
+static void runFinalizers(void)
+{
+	//fprintf(stderr, "RUNNING FINALIZERS\n");
+	if (finalizeThreaded)
+	{
+		dispatch_async_f(finalizer_queue, deferredFinalizer, NULL);
+	}
+	else
+	{
+		GC_invoke_finalizers();
+	}
+}
+
+PRIVATE void init_gc(void)
+{
+	//GC_no_dls = 1;
+	//GC_enable_incremental();
+	GC_INIT();
+	char *envValue;
+	// Dump GC stats on exit - uncomment when debugging.
+	if (getenv("LIBOBJC_DUMP_GC_STATUS_ON_EXIT"))
+	{
+		atexit(GC_dump);
+	}
+	if ((envValue = getenv("LIBOBJC_LOG_ALLOCATIONS")))
+	{
+		allocationLog = fopen(envValue, "a");
+	}
+	if ((envValue = getenv("LIBOBJC_CANARIES")))
+	{
+		unsigned s = envValue[0] ? strtol(envValue, NULL, 10) : 123;
+		srandom(s);
+		canarySize = sizeof(uint32_t);
+		canary = random();
+	}
+	if ((envValue = getenv("LIBOBJC_DUMP_GC_STATUS_ON_SIGNAL")))
+	{
+		int s = envValue[0] ? (int)strtol(envValue, NULL, 10) : SIGUSR2;
+		signal(s, collectAndDumpStats);
+	}
+	//GC_clear_roots();
+}
+
+BOOL objc_collecting_enabled(void)
+{
+	// Lock the GC in the current state once it's been queried.  This prevents
+	// the loading of any modules with an incompatible GC mode.
+	current_gc_mode = isGCEnabled ? GC_Required : GC_None;
+	return isGCEnabled;
+}
+
+void objc_startCollectorThread(void)
+{
+	if (YES == finalizeThreaded) { return; }
+	finalizer_queue = dispatch_queue_create("ObjC finalizeation thread", 0);
+	finalizeThreaded = YES;
+}
+
+void objc_clear_stack(unsigned long options)
+{
+	// This isn't a very good implementation - we should really be working out
+	// how much stack space is left somehow, but this is not possible to do
+	// portably.
+	int i[1024];
+	int *addr = &i[0];
+	memset(addr, 0, 1024);
+	// Tell the compiler that something that it doesn't know about is touching
+	// this memory, so it shouldn't optimise the allocation and memset away.
+	__asm__  volatile ("" :  : "m"(addr) : "memory");
+
+}
+BOOL objc_is_finalized(void *ptr)
+{
+	return *(Class*)ptr == zombie_class;
+}
+// FIXME: Stub implementation that should be replaced with something better
+void objc_finalizeOnMainThread(Class cls) {}
+
+static void *debug_malloc(size_t s)
+{
+	return GC_MALLOC_UNCOLLECTABLE(s);
+}
+static void debug_free(void *ptr)
+{
+	GC_FREE(ptr);
+}
+
+PRIVATE struct gc_ops gc_ops_boehm =
+{
+	.allocate_class = allocate_class,
+	.free_object    = free_object,
+	.malloc         = debug_malloc,
+	.free           = debug_free,
+};
+
+extern struct objc_class _NSConcreteStackBlock;
+void *_Block_copy(void *src);
+
+PRIVATE void enableGC(BOOL exclude)
+{
+	isGCEnabled = YES;
+	gc = &gc_ops_boehm;
+	refcount_initialize(&refcounts, 4096);
+	finalize = sel_registerName("finalize");
+	GC_finalizer_notifier = runFinalizers;
+}
diff --git a/third_party/libobjc/gc_none.c b/third_party/libobjc/gc_none.c
new file mode 100644
index 0000000000000000000000000000000000000000..ff4331d737af8fac947aba54a4e7e867d868a4b2
--- /dev/null
+++ b/third_party/libobjc/gc_none.c
@@ -0,0 +1,43 @@
+#include "visibility.h"
+#include "objc/runtime.h"
+#include "gc_ops.h"
+#include "class.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+static id allocate_class(Class cls, size_t extraBytes)
+{
+	intptr_t *addr = calloc(cls->instance_size + extraBytes + sizeof(intptr_t), 1);
+	return (id)(addr + 1);
+}
+
+static void free_object(id obj)
+{
+	free((void*)(((intptr_t*)obj) - 1));
+}
+
+static void *alloc(size_t size)
+{
+	return calloc(size, 1);
+}
+
+PRIVATE struct gc_ops gc_ops_none = 
+{
+	.allocate_class = allocate_class,
+	.free_object    = free_object,
+	.malloc         = alloc,
+	.free           = free
+};
+PRIVATE struct gc_ops *gc = &gc_ops_none;
+
+PRIVATE BOOL isGCEnabled = NO;
+
+#ifndef ENABLE_GC
+PRIVATE void enableGC(BOOL exclusive)
+{
+	fprintf(stderr, "Attempting to enable garbage collection, but your"
+			"Objective-C runtime was built without garbage collection"
+			"support\n");
+	abort();
+}
+#endif
diff --git a/third_party/libobjc/gc_ops.h b/third_party/libobjc/gc_ops.h
new file mode 100644
index 0000000000000000000000000000000000000000..5bd35a3ed5cd40599985f8078d259a2d75a02748
--- /dev/null
+++ b/third_party/libobjc/gc_ops.h
@@ -0,0 +1,79 @@
+
+/**
+ * Garbage collection operations.
+ */
+struct gc_ops
+{
+	/**
+	 * Initialises this collector.
+	 */
+	void (*init)(void);
+	/**
+	 * Allocates enough space for a class, followed by some extra bytes.
+	 */
+	id (*allocate_class)(Class, size_t);
+	/**
+	 * Frees an object.
+	 */
+	void (*free_object)(id);
+	/**
+	 * Allocates some memory that can be used to store pointers.  This must be
+	 * used instead of malloc() for internal data structures that will store
+	 * pointers passed in from outside.  The function is expected to zero the
+	 * memory that it returns.
+	 */
+	void* (*malloc)(size_t);
+	/**
+	 * Frees some memory that was previously used to store pointers.
+	 */
+	void (*free)(void*);
+};
+
+/**
+ * Enables garbage collection, if it isn't already enabled.
+ *
+ * If the exclusive flag is set, then this will ensure that all -retain /
+ * -release / -autorelease messages become no-ops.
+ */
+void enableGC(BOOL exclusive);
+
+/**
+ * The mode for garbage collection
+ */
+enum objc_gc_mode
+{
+	/** This module neither uses, nor supports, garbage collection. */
+	GC_None     = 0,
+	/**
+	 * This module uses garbage collection, but also sends retain / release
+	 * messages.  It can be used with or without GC.
+	 */
+	GC_Optional = 1,
+	/**
+	 * This module expects garbage collection and will break without it.
+	 */
+	GC_Required = 2,
+	/**
+	 * This module was compiled with automatic reference counting.  This
+	 * guarantees the use of the non-fragile ABI and means that we could
+	 * potentially support GC, although we don't currently.
+	 */
+	GC_ARC = 3
+};
+
+/**
+ * The current Objective-C garbage collection mode.
+ */
+extern enum objc_gc_mode current_gc_mode;
+/**
+ * Have we loaded any code that triggers the ObjC GC support?
+ */
+extern BOOL isGCEnabled;
+
+/**
+ * The current set of garbage collector operations to use.
+ */
+extern struct gc_ops *gc;
+
+extern struct gc_ops gc_ops_boehm;
+extern struct gc_ops gc_ops_none;
diff --git a/third_party/libobjc/hash_table.c b/third_party/libobjc/hash_table.c
new file mode 100644
index 0000000000000000000000000000000000000000..ee9cc001a2a600e418947de317ba666cd40521b9
--- /dev/null
+++ b/third_party/libobjc/hash_table.c
@@ -0,0 +1,22 @@
+#ifndef ENABLE_GC
+#include "objc/toydispatch.h"
+#include "lock.h"
+#include "visibility.h"
+
+
+static dispatch_queue_t garbage_queue;
+
+PRIVATE void objc_collect_garbage_data(void(*cleanup)(void*), void *garbage)
+{
+	if (0 == garbage_queue)
+	{
+		LOCK_RUNTIME_FOR_SCOPE();
+		if (0 == garbage_queue)
+		{
+			garbage_queue = dispatch_queue_create("ObjC deferred free queue", 0);
+		}
+	}
+	dispatch_async_f(garbage_queue, garbage, cleanup);
+}
+
+#endif
diff --git a/third_party/libobjc/hash_table.h b/third_party/libobjc/hash_table.h
new file mode 100644
index 0000000000000000000000000000000000000000..e064af1782a2daac76e3e9145e53d40abd18e0e0
--- /dev/null
+++ b/third_party/libobjc/hash_table.h
@@ -0,0 +1,560 @@
+/**
+ * hash_table.h provides a template for implementing hopscotch hash tables. 
+ *
+ * Several macros must be defined before including this file:
+ *
+ * MAP_TABLE_NAME defines the name of the table.  All of the operations and
+ * types related to this table will be prefixed with this value.
+ *
+ * MAP_TABLE_COMPARE_FUNCTION defines the function used for testing a key
+ * against a value in the table for equality.  This must take two void*
+ * arguments.  The first is the key and the second is the value.  
+ *
+ * MAP_TABLE_HASH_KEY and MAP_TABLE_HASH_VALUE define a pair of functions that
+ * takes a key and a value pointer respectively as their argument and returns
+ * an int32_t representing the hash.
+ *
+ * Optionally, MAP_TABLE_STATIC_SIZE may be defined, to define a table type
+ * which has a static size.
+ */
+#include "lock.h"
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+
+#ifdef ENABLE_GC
+#	include <gc/gc.h>
+#	include <gc/gc_typed.h>
+#	define CALLOC(x,y) GC_MALLOC(x*y)
+#	define IF_NO_GC(x)
+#	define IF_GC(x) x
+#else
+#	define CALLOC(x,y) calloc(x,y)
+#	define IF_NO_GC(x) x
+#	define IF_GC(x)
+#endif
+
+#ifndef MAP_TABLE_NAME
+#	error You must define MAP_TABLE_NAME.
+#endif
+#ifndef MAP_TABLE_COMPARE_FUNCTION
+#	error You must define MAP_TABLE_COMPARE_FUNCTION.
+#endif
+#ifndef MAP_TABLE_HASH_KEY 
+#	error You must define MAP_TABLE_HASH_KEY
+#endif
+#ifndef MAP_TABLE_HASH_VALUE
+#	error You must define MAP_TABLE_HASH_VALUE
+#endif
+
+// Horrible multiple indirection to satisfy the weird precedence rules in cpp
+#define REALLY_PREFIX_SUFFIX(x,y) x ## y
+#define PREFIX_SUFFIX(x, y) REALLY_PREFIX_SUFFIX(x, y)
+
+/**
+ * PREFIX(x) macro adds the table name prefix to the argument.
+ */
+#define PREFIX(x) PREFIX_SUFFIX(MAP_TABLE_NAME, x)
+
+
+/**
+ * Map tables are protected by a lock by default.  Defining MAP_TABLE_NO_LOCK
+ * will prevent this and make you responsible for synchronization.
+ */
+#ifdef MAP_TABLE_NO_LOCK
+#	define MAP_LOCK()
+#	define MAP_UNLOCK()
+#else
+#	define MAP_LOCK() (LOCK(&table->lock))
+#	define MAP_UNLOCK() (UNLOCK(&table->lock))
+#endif
+#ifndef MAP_TABLE_VALUE_TYPE
+#	define MAP_TABLE_VALUE_TYPE void*
+static BOOL PREFIX(_is_null)(void *value)
+{
+	return value == NULL;
+}
+#	define MAP_TABLE_TYPES_BITMAP 1
+#	define MAP_TABLE_VALUE_NULL PREFIX(_is_null)
+#	define MAP_TABLE_VALUE_PLACEHOLDER NULL
+#endif
+
+typedef struct PREFIX(_table_cell_struct)
+{
+	uint32_t secondMaps;
+	MAP_TABLE_VALUE_TYPE value;
+} *PREFIX(_table_cell);
+
+#ifdef MAP_TABLE_STATIC_SIZE
+typedef struct 
+{
+	mutex_t lock;
+	unsigned int table_used;
+	IF_NO_GC(unsigned int enumerator_count;)
+	struct PREFIX(_table_cell_struct) table[MAP_TABLE_STATIC_SIZE];
+} PREFIX(_table);
+static PREFIX(_table) MAP_TABLE_STATIC_NAME;
+#	ifndef MAP_TABLE_NO_LOCK
+__attribute__((constructor)) void static PREFIX(_table_initializer)(void)
+{
+	INIT_LOCK(MAP_TABLE_STATIC_NAME.lock);
+}
+#	endif
+#	define TABLE_SIZE(x) MAP_TABLE_STATIC_SIZE
+#else
+typedef struct PREFIX(_table_struct)
+{
+	mutex_t lock;
+	unsigned int table_size;
+	unsigned int table_used;
+	IF_NO_GC(unsigned int enumerator_count;)
+#	if defined(ENABLE_GC) && defined(MAP_TABLE_TYPES_BITMAP)
+	GC_descr descr;
+#	endif 
+	struct PREFIX(_table_struct) *old;
+	struct PREFIX(_table_cell_struct) *table;
+} PREFIX(_table);
+
+struct PREFIX(_table_cell_struct) *PREFIX(alloc_cells)(PREFIX(_table) *table, int count)
+{
+#	if defined(ENABLE_GC) && defined(MAP_TABLE_TYPES_BITMAP)
+	return GC_CALLOC_EXPLICITLY_TYPED(count,
+			sizeof(struct PREFIX(_table_cell_struct)), table->descr);
+#	else
+	return CALLOC(count, sizeof(struct PREFIX(_table_cell_struct)));
+#	endif
+}
+
+PREFIX(_table) *PREFIX(_create)(uint32_t capacity)
+{
+	PREFIX(_table) *table = CALLOC(1, sizeof(PREFIX(_table)));
+#	ifndef MAP_TABLE_NO_LOCK
+	INIT_LOCK(table->lock);
+#	endif
+#	if defined(ENABLE_GC) && defined(MAP_TABLE_TYPES_BITMAP)
+	// The low word in the bitmap stores the offsets of the next entries
+	GC_word bitmap = (MAP_TABLE_TYPES_BITMAP << 1);
+	table->descr = GC_make_descriptor(&bitmap,
+			sizeof(struct PREFIX(_table_cell_struct)) / sizeof (void*));
+#	endif
+	table->table = PREFIX(alloc_cells)(table, capacity);
+	table->table_size = capacity;
+	return table;
+}
+
+void PREFIX(_initialize)(PREFIX(_table) **table, uint32_t capacity)
+{
+#ifdef ENABLE_GC
+	GC_add_roots(table, table+1);
+#endif
+	*table = PREFIX(_create)(capacity);
+}
+
+#	define TABLE_SIZE(x) (x->table_size)
+#endif
+
+
+#ifdef MAP_TABLE_STATIC_SIZE
+static int PREFIX(_table_resize)(PREFIX(_table) *table)
+{
+	return 0;
+}
+#else
+
+static int PREFIX(_insert)(PREFIX(_table) *table, MAP_TABLE_VALUE_TYPE value);
+
+static int PREFIX(_table_resize)(PREFIX(_table) *table)
+{
+	struct PREFIX(_table_cell_struct) *newArray =
+		PREFIX(alloc_cells)(table, table->table_size * 2);
+	if (NULL == newArray) { return 0; }
+
+	// Allocate a new table structure and move the array into that.  Now
+	// lookups will try using that one, if possible.
+	PREFIX(_table) *copy = CALLOC(1, sizeof(PREFIX(_table)));
+	memcpy(copy, table, sizeof(PREFIX(_table)));
+	table->old = copy;
+
+	// Now we make the original table structure point to the new (empty) array.
+	table->table = newArray;
+	table->table_size *= 2;
+	// The table currently has no entries; the copy has them all.
+	table->table_used = 0;
+
+	// Finally, copy everything into the new table
+	// Note: we should really do this in a background thread.  At this stage,
+	// we can do the updates safely without worrying about read contention.
+	int copied = 0;
+	for (uint32_t i=0 ; i<copy->table_size ; i++)
+	{
+		MAP_TABLE_VALUE_TYPE value = copy->table[i].value;
+		if (!MAP_TABLE_VALUE_NULL(value))
+		{
+			copied++;
+			PREFIX(_insert)(table, value);
+		}
+	}
+	__sync_synchronize();
+	table->old = NULL;
+#	if !defined(ENABLE_GC) && defined(MAP_TABLE_SINGLE_THREAD)
+	free(copy);
+#	endif
+	return 1;
+}
+#endif
+
+struct PREFIX(_table_enumerator)
+{
+	PREFIX(_table) *table;
+	unsigned int seen;
+	unsigned int index;
+};
+
+static inline PREFIX(_table_cell) PREFIX(_table_lookup)(PREFIX(_table) *table, 
+                                                        uint32_t hash)
+{
+	hash = hash % TABLE_SIZE(table);
+	return &table->table[hash];
+}
+
+static int PREFIX(_table_move_gap)(PREFIX(_table) *table, uint32_t fromHash,
+		uint32_t toHash, PREFIX(_table_cell) emptyCell)
+{
+	for (uint32_t hash = fromHash - 32 ; hash < fromHash ; hash++)
+	{
+		// Get the cell n before the hash.
+		PREFIX(_table_cell) cell = PREFIX(_table_lookup)(table, hash);
+		// If this node is a primary entry move it down
+		if (MAP_TABLE_HASH_VALUE(cell->value) == hash)
+		{
+			emptyCell->value = cell->value;
+			cell->secondMaps |= (1 << ((fromHash - hash) - 1));
+			cell->value = MAP_TABLE_VALUE_PLACEHOLDER;
+			if (hash - toHash < 32)
+			{
+				return 1;
+			}
+			return PREFIX(_table_move_gap)(table, hash, toHash, cell);
+		}
+		int hop = __builtin_ffs(cell->secondMaps);
+		if (hop > 0 && (hash + hop) < fromHash)
+		{
+			PREFIX(_table_cell) hopCell = PREFIX(_table_lookup)(table, hash+hop);
+			emptyCell->value = hopCell->value;
+			// Update the hop bit for the new offset
+			cell->secondMaps |= (1 << ((fromHash - hash) - 1));
+			// Clear the hop bit in the original cell
+			cell->secondMaps &= ~(1 << (hop - 1));
+			hopCell->value = MAP_TABLE_VALUE_PLACEHOLDER;
+			if (hash - toHash < 32)
+			{
+				return 1;
+			}
+			return PREFIX(_table_move_gap)(table, hash + hop, toHash, hopCell);
+		}
+	}
+	return 0;
+}
+static int PREFIX(_table_rebalance)(PREFIX(_table) *table, uint32_t hash)
+{
+	for (unsigned i=32 ; i<TABLE_SIZE(table) ; i++)
+	{
+		PREFIX(_table_cell) cell = PREFIX(_table_lookup)(table, hash + i);
+		if (MAP_TABLE_VALUE_NULL(cell->value))
+		{
+			// We've found a free space, try to move it up.
+			return PREFIX(_table_move_gap)(table, hash + i, hash, cell);
+		}
+	}
+	return 0;
+}
+
+__attribute__((unused))
+static int PREFIX(_insert)(PREFIX(_table) *table, 
+                                 MAP_TABLE_VALUE_TYPE value)
+{
+	MAP_LOCK();
+	uint32_t hash = MAP_TABLE_HASH_VALUE(value);
+	PREFIX(_table_cell) cell = PREFIX(_table_lookup)(table, hash);
+	if (MAP_TABLE_VALUE_NULL(cell->value))
+	{
+		cell->secondMaps = 0;
+		cell->value = value;
+		table->table_used++;
+		MAP_UNLOCK();
+		return 1;
+	}
+	/* If this cell is full, try the next one. */
+	for (unsigned int i=0 ; i<32 ; i++)
+	{
+		PREFIX(_table_cell) second = 
+			PREFIX(_table_lookup)(table, hash+i);
+		if (MAP_TABLE_VALUE_NULL(second->value))
+		{
+			cell->secondMaps |= (1 << (i-1));
+			second->value = value;
+			table->table_used++;
+			MAP_UNLOCK();
+			return 1;
+		}
+	}
+	/* If the table is full, or nearly full, then resize it.  Note that we
+	 * resize when the table is at 80% capacity because it's cheaper to copy
+	 * everything than spend the next few updates shuffling everything around
+	 * to reduce contention.  A hopscotch hash table starts to degrade in
+	 * performance at around 90% capacity, so stay below that.
+	 */
+	if (table->table_used > (0.8 * TABLE_SIZE(table)))
+	{
+		PREFIX(_table_resize)(table);
+		MAP_UNLOCK();
+		return PREFIX(_insert)(table, value);
+	}
+	/* If this virtual cell is full, rebalance the hash from this point and
+	 * try again. */
+	if (PREFIX(_table_rebalance)(table, hash))
+	{
+		MAP_UNLOCK();
+		return PREFIX(_insert)(table, value);
+	}
+	/** If rebalancing failed, resize even if we are <80% full.  This can
+	 * happen if your hash function sucks.  If you don't want this to happen,
+	 * get a better hash function. */
+	if (PREFIX(_table_resize)(table))
+	{
+		MAP_UNLOCK();
+		return PREFIX(_insert)(table, value);
+	}
+	fprintf(stderr, "Insert failed\n");
+	MAP_UNLOCK();
+	return 0;
+}
+
+static void *PREFIX(_table_get_cell)(PREFIX(_table) *table, const void *key)
+{
+	uint32_t hash = MAP_TABLE_HASH_KEY(key);
+	PREFIX(_table_cell) cell = PREFIX(_table_lookup)(table, hash);
+	// Value does not exist.
+	if (!MAP_TABLE_VALUE_NULL(cell->value))
+	{
+		if (MAP_TABLE_COMPARE_FUNCTION(key, cell->value))
+		{
+			return cell;
+		}
+		uint32_t jump = cell->secondMaps;
+		// Look at each offset defined by the jump table to find the displaced location.
+		for (int hop = __builtin_ffs(jump) ; hop > 0 ; hop = __builtin_ffs(jump))
+		{
+			PREFIX(_table_cell) hopCell = PREFIX(_table_lookup)(table, hash+hop);
+			if (MAP_TABLE_COMPARE_FUNCTION(key, hopCell->value))
+			{
+				return hopCell;
+			}
+			// Clear the most significant bit and try again.
+			jump &= ~(1 << (hop-1));
+		}
+	}
+#ifndef MAP_TABLE_STATIC_SIZE
+	if (table->old)
+	{
+		return PREFIX(_table_get_cell)(table->old, key);
+	}
+#endif
+	return NULL;
+}
+
+__attribute__((unused))
+static void PREFIX(_table_move_second)(PREFIX(_table) *table, 
+		PREFIX(_table_cell) emptyCell)
+{
+	uint32_t jump = emptyCell->secondMaps;
+	// Look at each offset defined by the jump table to find the displaced location.
+	int hop = __builtin_ffs(jump);
+	PREFIX(_table_cell) hopCell = 
+		PREFIX(_table_lookup)(table, MAP_TABLE_HASH_VALUE(emptyCell->value) + hop);
+	emptyCell->value = hopCell->value;
+	emptyCell->secondMaps &= ~(1 << (hop-1));
+	if (0 == hopCell->secondMaps)
+	{
+		hopCell->value = MAP_TABLE_VALUE_PLACEHOLDER;
+	}
+	else
+	{
+		PREFIX(_table_move_second)(table, hopCell);
+	}
+}
+__attribute__((unused))
+static void PREFIX(_remove)(PREFIX(_table) *table, void *key)
+{
+	MAP_LOCK();
+	PREFIX(_table_cell) cell = PREFIX(_table_get_cell)(table, key);
+	if (NULL == cell) { return; }
+	// If the cell contains a value, set it to the placeholder and shuffle up
+	// everything
+	if (0 == cell->secondMaps)
+	{
+		cell->value = MAP_TABLE_VALUE_PLACEHOLDER;
+	}
+	else
+	{
+		PREFIX(_table_move_second)(table, cell);
+	}
+	table->table_used--;
+	MAP_UNLOCK();
+}
+
+__attribute__((unused))
+#ifdef MAP_TABLE_ACCESS_BY_REFERENCE
+static MAP_TABLE_VALUE_TYPE* 
+#else
+static MAP_TABLE_VALUE_TYPE 
+#endif
+	PREFIX(_table_get)(PREFIX(_table) *table,
+		const void *key)
+{
+	PREFIX(_table_cell) cell = PREFIX(_table_get_cell)(table, key);
+	if (NULL == cell)
+	{
+#ifdef MAP_TABLE_ACCESS_BY_REFERENCE
+		return NULL;
+#else
+		return MAP_TABLE_VALUE_PLACEHOLDER;
+#endif
+	}
+#ifdef MAP_TABLE_ACCESS_BY_REFERENCE
+	return &cell->value;
+#else
+	return cell->value;
+#endif
+}
+__attribute__((unused))
+static void PREFIX(_table_set)(PREFIX(_table) *table, const void *key,
+		MAP_TABLE_VALUE_TYPE value)
+{
+	PREFIX(_table_cell) cell = PREFIX(_table_get_cell)(table, key);
+	if (NULL == cell)
+	{
+		PREFIX(_insert)(table, value);
+	}
+	cell->value = value;
+}
+
+__attribute__((unused))
+#ifdef MAP_TABLE_ACCESS_BY_REFERENCE
+static MAP_TABLE_VALUE_TYPE* 
+#else
+static MAP_TABLE_VALUE_TYPE 
+#endif
+PREFIX(_next)(PREFIX(_table) *table,
+                    struct PREFIX(_table_enumerator) **state)
+{
+	if (NULL == *state)
+	{
+		*state = CALLOC(1, sizeof(struct PREFIX(_table_enumerator)));
+		// Make sure that we are not reallocating the table when we start
+		// enumerating
+		MAP_LOCK();
+		(*state)->table = table;
+		(*state)->index = -1;
+		IF_NO_GC(__sync_fetch_and_add(&table->enumerator_count, 1);)
+		MAP_UNLOCK();
+	}
+	if ((*state)->seen >= (*state)->table->table_used)
+	{
+#ifndef ENABLE_GC
+		MAP_LOCK();
+		__sync_fetch_and_sub(&table->enumerator_count, 1);
+		MAP_UNLOCK();
+		free(*state);
+#endif
+#ifdef MAP_TABLE_ACCESS_BY_REFERENCE
+		return NULL;
+#else
+		return MAP_TABLE_VALUE_PLACEHOLDER;
+#endif
+	}
+	while ((++((*state)->index)) < TABLE_SIZE((*state)->table))
+	{
+		if (!MAP_TABLE_VALUE_NULL((*state)->table->table[(*state)->index].value))
+		{
+			(*state)->seen++;
+#ifdef MAP_TABLE_ACCESS_BY_REFERENCE
+			return &(*state)->table->table[(*state)->index].value;
+#else
+			return (*state)->table->table[(*state)->index].value;
+#endif
+		}
+	}
+#ifndef ENABLE_GC
+	// Should not be reached, but may be if the table is unsafely modified.
+	MAP_LOCK();
+	table->enumerator_count--;
+	MAP_UNLOCK();
+	free(*state);
+#endif
+#ifdef MAP_TABLE_ACCESS_BY_REFERENCE
+	return NULL;
+#else
+	return MAP_TABLE_VALUE_PLACEHOLDER;
+#endif
+}
+/**
+ * Returns the current value for an enumerator.  This is used when you remove
+ * objects during enumeration.  It may cause others to be shuffled up the
+ * table.
+ */
+__attribute__((unused))
+#ifdef MAP_TABLE_ACCESS_BY_REFERENCE
+static MAP_TABLE_VALUE_TYPE* 
+#else
+static MAP_TABLE_VALUE_TYPE 
+#endif
+PREFIX(_current)(PREFIX(_table) *table,
+                    struct PREFIX(_table_enumerator) **state)
+{
+#ifdef MAP_TABLE_ACCESS_BY_REFERENCE
+	return &(*state)->table->table[(*state)->index].value;
+#else
+	return (*state)->table->table[(*state)->index].value;
+#endif
+}
+
+#undef TABLE_SIZE
+#undef REALLY_PREFIX_SUFFIX
+#undef PREFIX_SUFFIX
+#undef PREFIX
+
+#undef MAP_TABLE_NAME
+#undef MAP_TABLE_COMPARE_FUNCTION
+#undef MAP_TABLE_HASH_KEY
+#undef MAP_TABLE_HASH_VALUE
+
+#ifdef MAP_TABLE_STATIC_SIZE
+#	undef MAP_TABLE_STATIC_SIZE
+#endif
+
+#undef MAP_TABLE_VALUE_TYPE
+
+#undef MAP_LOCK
+#undef MAP_UNLOCK
+#ifdef MAP_TABLE_NO_LOCK
+#	undef MAP_TABLE_NO_LOCK
+#endif
+
+#ifdef MAP_TABLE_SINGLE_THREAD
+#	undef MAP_TABLE_SINGLE_THREAD
+#endif
+
+#undef MAP_TABLE_VALUE_NULL
+#undef MAP_TABLE_VALUE_PLACEHOLDER
+
+#ifdef MAP_TABLE_ACCESS_BY_REFERENCE
+#	undef MAP_TABLE_ACCESS_BY_REFERENCE
+#endif
+
+#undef CALLOC
+#undef IF_NO_GC
+#undef IF_GC
+#undef MAP_TABLE_TYPES_BITMAP
diff --git a/third_party/libobjc/hooks.c b/third_party/libobjc/hooks.c
new file mode 100644
index 0000000000000000000000000000000000000000..8def49b897a237f77c5feac296ffbde8f22572e4
--- /dev/null
+++ b/third_party/libobjc/hooks.c
@@ -0,0 +1,3 @@
+#include "objc/runtime.h"
+#define OBJC_HOOK
+#include "objc/hooks.h"
diff --git a/third_party/libobjc/ivar.c b/third_party/libobjc/ivar.c
new file mode 100644
index 0000000000000000000000000000000000000000..3c639aa35baa66a3948a25326aed4b92c71b241a
--- /dev/null
+++ b/third_party/libobjc/ivar.c
@@ -0,0 +1,143 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "objc/runtime.h"
+#include "class.h"
+#include "ivar.h"
+#include "visibility.h"
+
+ptrdiff_t objc_alignof_type(const char *);
+ptrdiff_t objc_sizeof_type(const char *);
+
+PRIVATE void objc_compute_ivar_offsets(Class class)
+{
+	int i = 0;
+	/* If this class was compiled with support for late-bound ivars, the
+	* instance_size field will contain 0 - {the size of the instance variables
+	* declared for just this class}.  The individual instance variable offset
+	* fields will then be the offsets from the start of the class, and so must
+	* have the size of the parent class prepended. */
+	if (class->instance_size <= 0)
+	{
+		Class super = class_getSuperclass(class);
+		long ivar_start = 0;
+		if (Nil != super)
+		{
+			if (super->instance_size <= 0)
+			{
+				objc_compute_ivar_offsets(super);
+			}
+			ivar_start = super->instance_size;
+		}
+		class->instance_size = ivar_start - class->instance_size;
+		/* For each instance variable, we add the offset if required (it will be zero
+		* if this class is compiled with a static ivar layout).  We then set the
+		* value of a global variable to the offset value.  
+		*
+		* Any class compiled with support for the non-fragile ABI, but not actually
+		* using it, will export the ivar offset field as a symbol.
+		*
+		* Note that using non-fragile ivars breaks @defs().  If you need equivalent
+		* functionality, provide an alternative @interface with all variables
+		* declared @public.
+		*/
+		if (class->ivars)
+		{
+			for (i = 0 ; i < class->ivars->count ; i++)
+			{
+				struct objc_ivar *ivar = &class->ivars->ivar_list[i];
+				ivar->offset += ivar_start;
+				/* If we're using the new ABI then we also set up the faster ivar
+				* offset variables.
+				*/
+				if (objc_test_class_flag(class, objc_class_flag_new_abi))
+				{
+					*(class->ivar_offsets[i]) = ivar->offset;
+				}
+			}
+		}
+	}
+	else
+	{
+		if (NULL == class->ivars) { return; }
+
+		Class super = class_getSuperclass(class);
+		int start = class->ivars->ivar_list[0].offset;
+		/* Quick and dirty test.  If the first ivar comes straight after the last
+		* class, then it's fine. */
+		if (Nil == super || start == super->instance_size) {return; }
+
+		/* Find the last superclass with at least one ivar. */
+		while (NULL == super->ivars) 
+		{
+			super = class_getSuperclass(super);
+		}
+		struct objc_ivar *ivar =
+			&super->ivars->ivar_list[super->ivars->count-1];
+
+		// Find the end of the last ivar - instance_size contains some padding
+		// for alignment.
+		int real_end = ivar->offset + objc_sizeof_type(ivar->type);
+		// Keep going if the new class starts at the end of the superclass
+		if (start == real_end)
+		{
+			return;
+		}
+		// The classes don't line up, but don't panic; check that the
+		// difference is not just padding for alignment
+		int align = objc_alignof_type(class->ivars->ivar_list[0].type);
+		if (start > real_end && (start - align) < real_end)
+		{
+			return;
+		}
+
+		/* Panic if this class has an instance variable that overlaps the
+		* superclass. */
+		fprintf(stderr, 
+			"Error: Instance variables in %s overlap superclass %s.  ",
+			class->name, super->name);
+		fprintf(stderr, 
+			"Offset of first instance variable, %s, is %d.  ",
+			class->ivars->ivar_list[0].name, start);
+		fprintf(stderr, 
+			"Last instance variable in superclass, %s, ends at offset %d.  ",
+			ivar->name, ivar->offset +
+			(int)objc_sizeof_type(ivar->type));
+		fprintf(stderr, "This probably means that you are subclassing a"
+			"class from a library, which has changed in a binary-incompatible"
+			"way.\n");
+		abort();
+	}
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Public API functions
+////////////////////////////////////////////////////////////////////////////////
+
+void object_setIvar(id object, Ivar ivar, id value)
+{
+	char *addr = (char*)object;
+	addr += ivar_getOffset(ivar);
+	*(id*)addr = value;
+}
+
+Ivar object_setInstanceVariable(id obj, const char *name, void *value)
+{
+	Ivar ivar = class_getInstanceVariable(object_getClass(obj), name);
+	object_setIvar(obj, ivar, value);
+	return ivar;
+}
+
+id object_getIvar(id object, Ivar ivar)
+{
+	return *(id*)(((char*)object) + ivar_getOffset(ivar));
+}
+
+Ivar object_getInstanceVariable(id obj, const char *name, void **outValue)
+{
+	Ivar ivar = class_getInstanceVariable(object_getClass(obj), name);
+	if (NULL != outValue)
+	{
+		*outValue = object_getIvar(obj, ivar);
+	}
+	return ivar;
+}
diff --git a/third_party/libobjc/ivar.h b/third_party/libobjc/ivar.h
new file mode 100644
index 0000000000000000000000000000000000000000..ea5a564b93fd90bed9e5fe8850bc2cd4944cb803
--- /dev/null
+++ b/third_party/libobjc/ivar.h
@@ -0,0 +1,47 @@
+
+/**
+ * Metadata structure for an instance variable.
+ *
+ * Note: The modern Apple runtime apparently stores the alignment of the ivar
+ * here.  We don't - we can compute it from the type, but it might be useful.
+ *
+ * It would also be good to add GC properties to this structure, and possibly
+ * an assignment policy (e.g. assign / retain / copy).
+ */
+struct objc_ivar
+{
+	/**
+	 * Name of this instance variable.
+	 */
+	const char *name;
+	/**
+	 * Type encoding for this instance variable.
+	 */
+	const char *type;
+	/**
+	 * The offset from the start of the object.  When using the non-fragile
+	 * ABI, this is initialized by the compiler to the offset from the start of
+	 * the ivars declared by this class.  It is then set by the runtime to the
+	 * offset from the object pointer.  
+	 */
+	int         offset;
+};
+
+/**
+ * A list of instance variables declared on this class.  Unlike the method
+ * list, this is a single array and size.  Categories are not allowed to add
+ * instance variables, because that would require existing objects to be
+ * reallocated, which is only possible with accurate GC (i.e. not in C).
+ */
+struct objc_ivar_list 
+{
+	/**
+	 * The number of instance variables in this list.
+	 */
+	int              count;
+	/**
+	 * An array of instance variable metadata structures.  Note that this array
+	 * has count elements.
+	 */
+	struct objc_ivar ivar_list[];
+};
diff --git a/third_party/libobjc/legacy_malloc.c b/third_party/libobjc/legacy_malloc.c
new file mode 100644
index 0000000000000000000000000000000000000000..3eedf2736752852725cb18342842d300ec1b0442
--- /dev/null
+++ b/third_party/libobjc/legacy_malloc.c
@@ -0,0 +1,43 @@
+#include <stdlib.h>
+
+void *valloc(size_t);
+
+// Stubs that just call the libc implementations when you call these.
+
+void *objc_malloc(size_t size)
+{
+	return malloc(size);
+}
+
+void *objc_atomic_malloc(size_t size)
+{
+	return malloc(size);
+}
+
+#ifdef __MINGW32__
+void *objc_valloc(size_t size)
+{
+	return malloc(size);
+}
+#else
+void *objc_valloc(size_t size)
+{
+	return valloc(size);
+}
+#endif
+
+void *objc_realloc(void *mem, size_t size)
+{
+	return realloc(mem, size);
+}
+
+void * objc_calloc(size_t nelem, size_t size)
+{
+	return calloc(nelem, size);
+}
+
+void objc_free(void *mem)
+{
+	free(mem);
+}
+
diff --git a/third_party/libobjc/loader.c b/third_party/libobjc/loader.c
new file mode 100644
index 0000000000000000000000000000000000000000..67a8cf5b95cd71957a4af862f84f1052774265cc
--- /dev/null
+++ b/third_party/libobjc/loader.c
@@ -0,0 +1,114 @@
+#include <stdlib.h>
+#include <assert.h>
+#include "objc/runtime.h"
+#include "lock.h"
+#include "loader.h"
+#include "visibility.h"
+#ifdef ENABLE_GC
+#include <gc/gc.h>
+#endif
+#include <stdio.h>
+
+/**
+ * Runtime lock.  This is exposed in 
+ */
+PRIVATE mutex_t runtime_mutex;
+LEGACY void *__objc_runtime_mutex = &runtime_mutex;
+
+void init_alias_table(void);
+void init_arc(void);
+void init_class_tables(void);
+void init_dispatch_tables(void);
+void init_gc(void);
+void init_protocol_table(void);
+void init_selector_tables(void);
+void init_trampolines(void);
+void objc_send_load_message(Class class);
+
+/* Number of threads that are alive.  */
+int __objc_runtime_threads_alive = 1;			/* !T:MUTEX */
+
+void __objc_exec_class(struct objc_module_abi_8 *module)
+{
+	static BOOL first_run = YES;
+
+	// Check that this module uses an ABI version that we recognise.  
+	// In future, we should pass the ABI version to the class / category load
+	// functions so that we can change various structures more easily.
+	assert(objc_check_abi_version(module));
+
+	if (first_run)
+	{
+#if ENABLE_GC
+		init_gc();
+#endif
+		// Create the main runtime lock.  This is not safe in theory, but in
+		// practice the first time that this function is called will be in the
+		// loader, from the main thread.  Future loaders may run concurrently,
+		// but that is likely to break the semantics of a lot of languages, so
+		// we don't have to worry about it for a long time.
+		//
+		// The only case when this can potentially go badly wrong is when a
+		// pure-C main() function spawns two threads which then, concurrently,
+		// call dlopen() or equivalent, and the platform's implementation of
+		// this does not perform any synchronization.
+		INIT_LOCK(runtime_mutex);
+		// Create the various tables that the runtime needs.
+		init_selector_tables();
+		init_protocol_table();
+		init_class_tables();
+		init_dispatch_tables();
+		init_alias_table();
+		init_arc();
+		init_trampolines();
+		first_run = NO;
+	}
+
+	// The runtime mutex is held for the entire duration of a load.  It does
+	// not need to be acquired or released in any of the called load functions.
+	LOCK_RUNTIME_FOR_SCOPE();
+
+	struct objc_symbol_table_abi_8 *symbols = module->symbol_table;
+	// Register all of the selectors used in this module.
+	if (symbols->selectors)
+	{
+		objc_register_selector_array(symbols->selectors,
+				symbols->selector_count);
+	}
+
+	unsigned short defs = 0;
+	// Load the classes from this module
+	for (unsigned short i=0 ; i<symbols->class_count ; i++)
+	{
+		objc_load_class(symbols->definitions[defs++]);
+	}
+	unsigned int category_start = defs;
+	// Load the categories from this module
+	for (unsigned short i=0 ; i<symbols->category_count; i++)
+	{
+		objc_try_load_category(symbols->definitions[defs++]);
+	}
+	// Load the static instances
+	struct objc_static_instance_list **statics = (void*)symbols->definitions[defs];
+	while (NULL != statics && NULL != *statics)
+	{
+		objc_init_statics(*(statics++));
+	}
+
+	// Load categories and statics that were deferred.
+	objc_load_buffered_categories();
+	objc_init_buffered_statics();
+	// Fix up the class links for loaded classes.
+	objc_resolve_class_links();
+	for (unsigned short i=0 ; i<symbols->category_count; i++)
+	{
+		struct objc_category *cat = (struct objc_category*)
+			symbols->definitions[category_start++];
+		Class class = (Class)objc_getClass(cat->class_name);
+		if ((Nil != class) && 
+		    objc_test_class_flag(class, objc_class_flag_resolved))
+		{
+			objc_send_load_message(class);
+		}
+	}
+}
diff --git a/third_party/libobjc/loader.h b/third_party/libobjc/loader.h
new file mode 100644
index 0000000000000000000000000000000000000000..a97063bdc067eda85dd8bf760c94734c909616d7
--- /dev/null
+++ b/third_party/libobjc/loader.h
@@ -0,0 +1,67 @@
+#ifndef __OBJC_LOADER_H_INCLUDED
+#define __OBJC_LOADER_H_INCLUDED
+#include "category.h"
+#include "method_list.h"
+#include "module.h"
+#include "class.h"
+#include "protocol.h"
+
+/**
+ * Checks whether it is safe to load a module with the specified version and
+ * module size.  This depends on whether another module with an incompatible
+ * ABI has already been loaded.
+ */
+BOOL objc_check_abi_version(struct objc_module_abi_8 *module);
+/**
+ * Initializes a protocol list, uniquing the protocols in the list.
+ */
+void objc_init_protocols(struct objc_protocol_list *protocols);
+/**
+ * Registers a set of selectors from a method list.
+ */
+void objc_register_selectors_from_list(struct objc_method_list *l);
+/**
+ * Register all of the (unregistered) selectors that are used in a class.
+ */
+void objc_register_selectors_from_class(Class class);
+/**
+ * Registers all of the selectors in an array.
+ */
+void objc_register_selector_array(SEL selectors, unsigned long count);
+/**
+ * Loads a class into the runtime system.  If possible, the class is resolved
+ * (inserted into the class tree) immediately.  If its superclass is not yet
+ * resolved, it is enqueued for later resolution.
+ */
+void objc_load_class(struct objc_class *class);
+/**
+ * Resolves classes that have not yet been resolved, if their superclasses have
+ * subsequently been loaded.
+ */
+void objc_resolve_class_links(void);
+/**
+ * Attaches a category to its class, if the class is already loaded.  Buffers
+ * it for future resolution if not.
+ */
+void objc_try_load_category(struct objc_category *cat);
+/**
+ * Tries to load all of the categories that could not previously be loaded
+ * because their classes were not yet loaded.
+ */
+void objc_load_buffered_categories(void);
+/**
+ * Updates the dispatch table for a class.  
+ */
+void objc_update_dtable_for_class(Class cls);
+/**
+ * Initialises a list of static object instances belonging to the same class if
+ * possible, or defers initialisation until the class has been loaded it not.
+ */
+void objc_init_statics(struct objc_static_instance_list *statics);
+/**
+ * Tries again to initialise static instances which could not be initialised
+ * earlier.
+ */
+void objc_init_buffered_statics(void);
+
+#endif //__OBJC_LOADER_H_INCLUDED
diff --git a/third_party/libobjc/lock.h b/third_party/libobjc/lock.h
new file mode 100644
index 0000000000000000000000000000000000000000..527c8714f845b968ef8bdb5ecbc346baa08b3ce2
--- /dev/null
+++ b/third_party/libobjc/lock.h
@@ -0,0 +1,70 @@
+/**
+ * libobjc requires recursive mutexes.  These are delegated to the underlying
+ * threading implementation.  This file contains a VERY thin wrapper over the
+ * Windows and POSIX mutex APIs.
+ */
+
+#ifndef __LIBOBJC_LOCK_H_INCLUDED__
+#define __LIBOBJC_LOCK_H_INCLUDED__
+#ifdef WIN32
+#define BOOL _WINBOOL
+#	include <windows.h>
+#undef BOOL
+typedef HANDLE mutex_t;
+#	define INIT_LOCK(x) x = CreateMutex(NULL, FALSE, NULL)
+#	define LOCK(x) WaitForSingleObject(*x, INFINITE)
+#	define UNLOCK(x) ReleaseMutex(*x)
+#	define DESTROY_LOCK(x) CloseHandle(*x)
+#else
+
+#	include <pthread.h>
+
+typedef pthread_mutex_t mutex_t;
+// If this pthread implementation has a static initializer for recursive
+// mutexes, use that, otherwise fall back to the portable version
+#	ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
+#		define INIT_LOCK(x) x = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
+#	elif defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER)
+#		define INIT_LOCK(x) x = PTHREAD_RECURSIVE_MUTEX_INITIALIZER
+#	else
+#		define INIT_LOCK(x) init_recursive_mutex(&(x))
+
+static inline void init_recursive_mutex(pthread_mutex_t *x)
+{
+	pthread_mutexattr_t recursiveAttributes;
+	pthread_mutexattr_init(&recursiveAttributes);
+	pthread_mutexattr_settype(&recursiveAttributes, PTHREAD_MUTEX_RECURSIVE);
+	pthread_mutex_init(x, &recursiveAttributes);
+	pthread_mutexattr_destroy(&recursiveAttributes);
+}
+#	endif
+
+#	define LOCK(x) pthread_mutex_lock(x)
+#	define UNLOCK(x) pthread_mutex_unlock(x)
+#	define DESTROY_LOCK(x) pthread_mutex_destroy(x)
+#endif
+
+__attribute__((unused)) static void objc_release_lock(void *x)
+{
+	mutex_t *lock = *(mutex_t**)x;
+	UNLOCK(lock);
+}
+/**
+ * Acquires the lock and automatically releases it at the end of the current
+ * scope.
+ */
+#define LOCK_FOR_SCOPE(lock) \
+	__attribute__((cleanup(objc_release_lock)))\
+	__attribute__((unused)) mutex_t *lock_pointer = lock;\
+	LOCK(lock)
+
+/**
+ * The global runtime mutex.
+ */
+extern mutex_t runtime_mutex;
+
+#define LOCK_RUNTIME() LOCK(&runtime_mutex)
+#define UNLOCK_RUNTIME() UNLOCK(&runtime_mutex)
+#define LOCK_RUNTIME_FOR_SCOPE() LOCK_FOR_SCOPE(&runtime_mutex)
+
+#endif // __LIBOBJC_LOCK_H_INCLUDED__
diff --git a/third_party/libobjc/method_list.h b/third_party/libobjc/method_list.h
new file mode 100644
index 0000000000000000000000000000000000000000..5a839077801a71e764305fa83ef7aacae348220b
--- /dev/null
+++ b/third_party/libobjc/method_list.h
@@ -0,0 +1,43 @@
+/**
+ * Metadata structure describing a method.  
+ */
+struct objc_method
+{
+	/**
+	 * Selector used to send messages to this method.  The type encoding of
+	 * this method should match the types field.
+	 */
+	SEL         selector;
+	/**
+	 * The type encoding for this selector.  Used only for introspection, and
+	 * only required because of the stupid selector handling in the old GNU
+	 * runtime.  In future, this field may be reused for something else.
+	 */
+	const char *types;
+	/**
+	 * A pointer to the function implementing this method.
+	 */
+	IMP         imp;
+};
+
+/**
+ * Method list.  Each class or category defines a new one of these and they are
+ * all chained together in a linked list, with new ones inserted at the head.
+ * When constructing the dispatch table, methods in the start of the list are
+ * used in preference to ones at the end.
+ */
+struct objc_method_list
+{
+	/**
+	 * The next group of methods in the list.
+	 */
+	struct objc_method_list  *next;
+	/**
+	 * The number of methods in this list.
+	 */
+	int                       count;
+	/**
+	 * An array of methods.  Note that the actual size of this is count.
+	 */
+	struct objc_method        methods[];
+};
diff --git a/third_party/libobjc/module.h b/third_party/libobjc/module.h
new file mode 100644
index 0000000000000000000000000000000000000000..96e0a773c49f95a247289d9347d510eaf67a0018
--- /dev/null
+++ b/third_party/libobjc/module.h
@@ -0,0 +1,102 @@
+/**
+ * Defines the module structures.
+ *
+ * When defining a new ABI, the 
+ */
+
+/**
+ * The symbol table for a module.  This structure references all of the
+ * Objective-C symbols defined for a module, allowing the runtime to find and
+ * register them.
+ */
+struct objc_symbol_table_abi_8
+{
+	/**
+	 * The number of selectors referenced in this module.
+	 */
+	unsigned long  selector_count;
+	/**
+	 * An array of selectors used in this compilation unit.  SEL is a pointer
+	 * type and this points to the first element in an array of selectors.
+	 */
+	SEL            selectors;
+	/**
+	 * The number of classes defined in this module.
+	 */
+	unsigned short class_count;
+	/**
+	 * The number of categories defined in this module.
+	 */
+	unsigned short category_count;
+	/**
+	 * A null-terminated array of pointers to symbols defined in this module.
+	 * This contains class_count pointers to class structures, category_count
+	 * pointers to category structures, and then zero or more pointers to
+	 * static object instances.
+	 *
+	 * Current compilers only use this for constant strings.  The runtime
+	 * permits other types.
+	 */
+	void           *definitions[];
+};
+
+/**
+ * The module structure is passed to the __objc_exec_class function by a
+ * constructor function when the module is loaded.  
+ *
+ * When defining a new ABI version, the first two fields in this structure must
+ * be retained.
+ */
+struct objc_module_abi_8
+{
+	/**
+	 * The version of the ABI used by this module.  This is checked against the
+	 * list of ABIs that the runtime supports, and the list of incompatible
+	 * ABIs.
+	 */
+	unsigned long                   version;
+	/**
+	 * The size of the module.  This is used for sanity checking, to ensure
+	 * that the compiler and runtime's idea of the module size match.
+	 */
+	unsigned long                   size;
+	/**
+	 * The full path name of the source for this module.  Not currently used
+	 * for anything, could be used for debugging in theory, but duplicates
+	 * information available from DWARF data, so probably won't.
+	 */
+	const char                     *name;
+	/**
+	 * A pointer to the symbol table for this compilation unit.
+	 */
+	struct objc_symbol_table_abi_8 *symbol_table;
+};
+
+struct objc_module_abi_10
+{
+	/**
+	 * Inherited fields from version 8 of the ABI.
+	 */
+	struct objc_module_abi_8 old;
+	/**
+	 * GC mode.  GC_Optional code can be mixed with anything, but GC_None code
+	 * can't be mixed with GC_Required code.
+	 */
+	int gc_mode;
+};
+
+/**
+ * List of static instances of a named class provided in this module.
+ */
+struct objc_static_instance_list
+{
+	/**
+	 * The name of the class.  The isa pointer of all of the instances will be
+	 * set to the class with this name.
+	 */
+	char *class_name;
+	/**
+	 * NULL-terminated array of statically-allocated instances.
+	 */
+	id    instances[];
+};
diff --git a/third_party/libobjc/mutation.m b/third_party/libobjc/mutation.m
new file mode 100644
index 0000000000000000000000000000000000000000..867cbb704b4bb948c13a8f1a4ec0eefcd926e3da
--- /dev/null
+++ b/third_party/libobjc/mutation.m
@@ -0,0 +1,12 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "objc/runtime.h"
+
+// This function is exported as a weak symbol to enable GNUstep or some other
+// framework to replace it trivially
+void __attribute__((weak)) objc_enumerationMutation(id obj)
+{
+	fprintf(stderr, "Mutation occured during enumeration.");
+	abort();
+}
+
diff --git a/third_party/libobjc/nsobject.h b/third_party/libobjc/nsobject.h
new file mode 100644
index 0000000000000000000000000000000000000000..7703a225e96634d9633b0737c2a333d3e27f8ef2
--- /dev/null
+++ b/third_party/libobjc/nsobject.h
@@ -0,0 +1,10 @@
+/**
+ * Stub declaration of NSObject.  Lots of things in the runtime require the 
+ */
+@interface NSObject
+-retain;
+-copy;
+-(void)release;
+-autorelease;
+-(void)dealloc;
+@end
diff --git a/third_party/libobjc/objc/Availability.h b/third_party/libobjc/objc/Availability.h
new file mode 100644
index 0000000000000000000000000000000000000000..408b9988ca42a017b6f9026803a2e3107db2291e
--- /dev/null
+++ b/third_party/libobjc/objc/Availability.h
@@ -0,0 +1,20 @@
+
+#ifdef STRICT_MACOS_X
+#	define OBJC_NONPORTABLE __attribute__((error("Function not supported by the Apple runtime")))
+#else
+#	define OBJC_NONPORTABLE
+#endif
+
+#if !defined(__DEPRECATE_DIRECT_ACCESS) || defined(__OBJC_LEGACY_GNU_MODE__) || defined(__OBJC_RUNTIME_INTERNAL__)
+#	define OBJC_DEPRECATED
+#else
+#	define OBJC_DEPRECATED __attribute__((deprecated))
+#endif
+
+#ifdef ERROR_UNSUPPORTED_RUNTIME_FUNCTIONS
+#	define OBJC_GNUSTEP_RUNTIME_UNSUPPORTED(x) \
+		__attribute__((error(x " not supported by this runtime")))
+#else
+#	define OBJC_GNUSTEP_RUNTIME_UNSUPPORTED(x)
+#endif
+
diff --git a/third_party/libobjc/objc/Object.h b/third_party/libobjc/objc/Object.h
new file mode 100644
index 0000000000000000000000000000000000000000..e5c9c4669d83e78b575bf8b1470632e333db37d0
--- /dev/null
+++ b/third_party/libobjc/objc/Object.h
@@ -0,0 +1,7 @@
+#include <objc/runtime.h>
+
+@interface Object
+{
+	Class isa;
+}
+@end
diff --git a/third_party/libobjc/objc/Protocol.h b/third_party/libobjc/objc/Protocol.h
new file mode 100644
index 0000000000000000000000000000000000000000..d38c1f51d3be072be68c1d4ac747f173c3932a47
--- /dev/null
+++ b/third_party/libobjc/objc/Protocol.h
@@ -0,0 +1,3 @@
+#import "Object.h"
+
+@interface Protocol : Object @end
diff --git a/third_party/libobjc/objc/blocks_private.h b/third_party/libobjc/objc/blocks_private.h
new file mode 100644
index 0000000000000000000000000000000000000000..5f1fca15586461d5c6478576082d7b17b5bb5432
--- /dev/null
+++ b/third_party/libobjc/objc/blocks_private.h
@@ -0,0 +1,90 @@
+#ifndef __LIBOBJC_BLOCKS_PRIVATE_H_INCLUDED__
+#define __LIBOBJC_BLOCKS_PRIVATE_H_INCLUDED__
+
+/*
+ * This header file exposes some implementation details of the blocks runtime
+ * that are needed, e.g., by libdispatch.
+ */
+
+
+/**
+ * Block descriptor that contains copy and dispose operations.
+ */
+struct Block_descriptor
+{
+	/**
+	 * Reserved for future use.  Currently always 0.
+	 */
+	unsigned long int reserved;
+	/** Size of the block. */
+	unsigned long int size;
+	/**
+	 * Copy function, generated by the compiler to help copy the block if it
+	 * contains nontrivial copy operations.
+	 */
+	void (*copy_helper)(void *dst, void *src);
+	/**
+	 * Dispose function, generated by the compiler to help copy the block if it
+	 * contains nontrivial destructors.
+	 */
+	void (*dispose_helper)(void *src);
+	/**
+	 * Objective-C type encoding of the block.
+	 */
+	const char *encoding;
+};
+
+// Helper structure
+struct Block_layout
+{
+	/**
+	 * Class pointer.  Always initialised to &_NSConcreteStackBlock for blocks
+	 * that are created on the stack or &_NSConcreteGlobalBlock for blocks that
+	 * are created in global storage.
+	 */
+	void *isa;
+	/**
+	 * Flags.  See the block_flags enumerated type for possible values.
+	 */
+	int flags;
+	/**
+	 * Reserved - always initialised to 0 by the compiler.  Used for the
+	 * reference count in this implementation.
+	 */
+	int reserved;
+	/**
+	 * The function that implements the block.  The first argument is this
+	 * structure, the subsequent arguments are the block's explicit parameters.
+	 * If the BLOCK_USE_SRET flag is set, there is an additional hidden
+	 * argument, which is a pointer to the space on the stack allocated to hold
+	 * the return value.
+	 */
+	void (*invoke)(void *, ...);
+	/**
+	 * The block's descriptor.  This is either Block_descriptor_basic or
+	 * Block_descriptor, depending on whether the
+	 * BLOCK_HAS_COPY_DISPOSE flag is set.
+	 */
+	struct Block_descriptor *descriptor;
+	/**
+	 * Block variables are appended to this structure.
+	 */
+};
+
+
+
+#ifndef __OBJC_RUNTIME_INTERNAL__
+/*
+ * Deprecated Block_basic datastructure needed by libdispatch
+ */
+struct Block_basic {
+	void *isa;
+	int Block_flags;
+	int Block_size;
+	void (*Block_invoke)(void *);
+	void (*Block_copy)(void *dst, void *src);
+	void (*Block_dispose)(void *);
+};
+#endif // __OBJC_RUNTIME_INTERNAL__
+#endif  //__LIBOBJC_BLOCKS_PRIVATE_H_INCLUDED__
+
diff --git a/third_party/libobjc/objc/blocks_runtime.h b/third_party/libobjc/objc/blocks_runtime.h
new file mode 100644
index 0000000000000000000000000000000000000000..8a64bf2fd5e36114ff45e63e464792d213abef09
--- /dev/null
+++ b/third_party/libobjc/objc/blocks_runtime.h
@@ -0,0 +1,17 @@
+/*
+ * Blocks Runtime
+ */
+
+#include "Availability.h"
+#ifdef __cplusplus
+#define BLOCKS_EXPORT extern "C"
+#else
+#define BLOCKS_EXPORT extern 
+#endif
+
+BLOCKS_EXPORT void *_Block_copy(void *);
+BLOCKS_EXPORT void _Block_release(void *);
+BLOCKS_EXPORT const char *block_getType_np(void *b) OBJC_NONPORTABLE;
+
+#define Block_copy(x) ((__typeof(x))_Block_copy((void *)(x)))
+#define Block_release(x) _Block_release((void *)(x))
diff --git a/third_party/libobjc/objc/capabilities.h b/third_party/libobjc/objc/capabilities.h
new file mode 100644
index 0000000000000000000000000000000000000000..950749c0805b37ee8840563aea34932493398afc
--- /dev/null
+++ b/third_party/libobjc/objc/capabilities.h
@@ -0,0 +1,136 @@
+/**
+ * capabilities.h - This file defines the list of capabilities.  Runtime
+ * capabilities can be checked.  You may use #ifdef to test at compile time
+ * whether the runtime on the current platform understands the capability.
+ * This does not mean that the runtime implements the capability, however.
+ *
+ * A copy of this file exists for compatibility in GNUstep's Objective-C
+ * framework.  When using this framework in conjunction with the GNU
+ * Objective-C runtime, most of the features will not be supported at run time,
+ * even if the corresponding macros are available at compile time.
+ * Additionally, several are compile-time options in the GNUstep runtime, so
+ * although they are present in the header and understood by the runtime, they
+ * may not be supported by the installed runtime.
+ */
+#include "Availability.h"
+
+#ifndef __GNUSTEP_CAPABILITIES_H__
+#	define __GNUSTEP_CAPABILITIES_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The runtime supports zero-cost exceptions.
+ */
+#define OBJC_CAP_EXCEPTIONS              0
+/**
+ * The runtime supports the @synchronize directive.
+ */
+#define OBJC_CAP_SYNCRONIZE              1
+/**
+ * The runtime supports property accessors.
+ */
+#define OBJC_CAP_PROPERTIES              2
+/**
+ * The runtime supports introspection on declared properties.
+ */
+#define OBJC_CAP_PROPERTY_INTROSPECTION  3
+/**
+ * The runtime supports optional methods and declared properties in protocols.
+ */
+#define OBJC_CAP_OPTIONAL_PROTOCOLS      4
+/**
+ * The runtime supports non-fragile instance variables.
+ */
+#define OBJC_CAP_NONFRAGILE_IVARS        5
+/**
+ * The runtime supports making method lookup dependent on the types, as well as
+ * the name, of the selector.
+ */
+#define OBJC_CAP_TYPE_DEPENDENT_DISPATCH 6
+/**
+ * The runtime was compiled in the low-memory profile.  This trades some speed
+ * for reduced memory consumption.
+ */
+#define OBJC_CAP_LOW_MEMORY              7
+/**
+ * The runtime supports developer mode.  When in user mode (the default),
+ * loading two classes with the same name will cause the program to abort.  In
+ * developer mode, the new class will replace the old one.  If the ivar layouts
+ * are the same, the new class will be treated as a category.  If they are
+ * different, then it will replace the old one in the class table, meaning that
+ * message sends to the class will go to the new version, but existing
+ * instances will not acquire the new methods.
+ */
+#define OBJC_DEVELOPER_MODE              8
+/**
+ * This runtime supports the unified exception model.  This means that
+ * Objective-C objects can be caught by either Objective-C or C++ exception
+ * handlers (the latter only in Objective-C++ code), irrespective of whether
+ * they are thrown from C++ throw of Objective-C @throw statements.
+ */
+#define OBJC_UNIFIED_EXCEPTION_MODEL     9
+
+/**
+ * The runtime provides a hook that allows the compiler to register class
+ * aliases declared with the @compatibility_alias keyword. This allows the
+ * runtime to resolve the alias, e.g. if objc_getClass() is called with an
+ * alias as the argument.
+ */
+#define OBJC_CAP_REGISTERED_COMPATIBILITY_ALIASES	10
+/**
+ * The runtime supports automatic reference counting, including support for
+ * __weak references.
+ */
+#define OBJC_CAP_ARC 11
+/**
+ * The runtime has support for garbage collection, as introduced by OS X 10.5.
+ * This includes implementations of a set of write barrier functions.
+ */
+#define OBJC_CAP_GARBAGE_COLLECTION 12
+/**
+ * The runtime has support for associated references, as introduced with OS X
+ * 10.6.  The objc_setAssociatedObject() and objc_getAssociatedObject()
+ * functions are available.
+ */
+#define OBJC_CAP_ASSOCIATED_REFERENCES 13
+/**
+ * The runtime supports storing objects in pointers.
+ */
+#define OBJC_CAP_SMALL_OBJECTS 14
+/**
+ * The runtime supports prototype-based object orientation.
+ */
+#define OBJC_CAP_PROTOTYPES 15
+/**
+ * The runtime provides APIs for debugging ARC-managed autorelease pools.
+ */
+#define OBJC_ARC_AUTORELEASE_DEBUG 16
+
+/**
+ * Macro used to require the existence of a specific capability.  This creates
+ * a function that is called by the loader and tests that the runtime supports
+ * the required capability, aborting if it does not.
+ */
+#define OBJC_REQUIRE_CAPABILITY(x) \
+	__attribute__((constructor)) static void objc_test ## x(void)\
+	{\
+		if (!objc_test_capability(x))\
+		{\
+			fprintf(stderr, "Runtime does not support required feature: " #x "\n");\
+			exit(1);\
+		}\
+	}
+
+/**
+ * Run time feature test.  This function returns 1 if the runtime supports the
+ * specified feature or 0 if it does not.
+ */
+int objc_test_capability(int x) OBJC_NONPORTABLE;
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__GNUSTEP_CAPABILITIES_H__
diff --git a/third_party/libobjc/objc/developer.h b/third_party/libobjc/objc/developer.h
new file mode 100644
index 0000000000000000000000000000000000000000..2752cf12d5fd0d31bfcca4b45b3c9999086b2142
--- /dev/null
+++ b/third_party/libobjc/objc/developer.h
@@ -0,0 +1,21 @@
+enum objc_developer_mode_np
+{
+	/** User mode - the default. */
+	objc_developer_mode_user,
+	/** Developer mode - allows replacing classes. */
+	objc_developer_mode_developer
+};
+/*
+ * Sets the developer mode.  When in user mode (the default),
+ * loading two classes with the same name will cause the program to abort.  In
+ * developer mode, the new class will replace the old one.  If the ivar layouts
+ * are the same, the new class will be treated as a category.  If they are
+ * different, then it will replace the old one in the class table, meaning that
+ * message sends to the class will go to the new version, but existing
+ * instances will not acquire the new methods.
+ *
+ * The runtime currently only supports two modes, although more may be added in
+ * the future.  The behaviour of the existing modes will be maintained if this
+ * is the case.
+ */
+void objc_setDeveloperMode_np(enum objc_developer_mode_np);
diff --git a/third_party/libobjc/objc/encoding.h b/third_party/libobjc/objc/encoding.h
new file mode 100644
index 0000000000000000000000000000000000000000..bb58c0b8c4b40a4f5eed60acbf8990c2ea1320db
--- /dev/null
+++ b/third_party/libobjc/objc/encoding.h
@@ -0,0 +1,70 @@
+#ifndef __LIBOBJC_ENCODING_H_INCLUDED__
+#define __LIBOBJC_ENCODING_H_INCLUDED__
+
+const char *objc_skip_type_qualifiers (const char *type);
+
+const char *objc_skip_typespec(const char *type);
+
+const char *objc_skip_argspec(const char *type);
+
+
+size_t objc_sizeof_type(const char *type);
+
+size_t objc_alignof_type(const char *type);
+
+size_t objc_aligned_size(const char *type);
+
+size_t objc_promoted_size(const char *type);
+
+void method_getReturnType(Method method, char *dst, size_t dst_len);
+
+const char *method_getTypeEncoding(Method method);
+
+void method_getArgumentType(Method method,
+                            unsigned int index,
+                            char *dst,
+                            size_t dst_len);
+
+unsigned method_getNumberOfArguments(Method method);
+
+unsigned method_get_number_of_arguments(struct objc_method *method);
+
+char * method_copyArgumentType(Method method, unsigned int index);
+
+char * method_copyReturnType(Method method);
+
+////////////////////////////////////////////////////////////////////////////////
+// Deprecated functions - do not use functions below this line in new code.
+////////////////////////////////////////////////////////////////////////////////
+unsigned objc_get_type_qualifiers (const char *type);
+
+struct objc_struct_layout
+{
+	const char *original_type;
+	const char *type;
+	const char *prev_type;
+	unsigned int record_size;
+	unsigned int record_align;
+};
+
+// Note: The implementations of these functions is horrible.
+void objc_layout_structure (const char *type,
+                            struct objc_struct_layout *layout);
+
+BOOL objc_layout_structure_next_member(struct objc_struct_layout *layout);
+
+void objc_layout_structure_get_info (struct objc_struct_layout *layout,
+                                     unsigned int *offset,
+                                     unsigned int *align,
+                                     const char **type);
+
+#define _F_CONST       0x01
+#define _F_IN          0x01
+#define _F_OUT         0x02
+#define _F_INOUT       0x03
+#define _F_BYCOPY      0x04
+#define _F_BYREF       0x08
+#define _F_ONEWAY      0x10
+#define _F_GCINVISIBLE 0x20
+
+#endif // __LIBOBJC_ENCODING_H_INCLUDED__
diff --git a/third_party/libobjc/objc/hooks.h b/third_party/libobjc/objc/hooks.h
new file mode 100644
index 0000000000000000000000000000000000000000..7fdcf88091311cb91254b863b54739843b570e68
--- /dev/null
+++ b/third_party/libobjc/objc/hooks.h
@@ -0,0 +1,74 @@
+/**
+ * This file includes all of the hooks that can be used to alter the behaviour
+ * of the runtime.  
+ */
+
+
+#ifndef OBJC_HOOK
+#define OBJC_HOOK extern
+#endif
+struct objc_category;
+/**
+ * Class lookup hook.  Set this to provide a mechanism for resolving classes
+ * that have not been registered with the runtime.  This can be used for lazy
+ * library loading, for example.  The hook takes a class name as an argument
+ * and returns the class.  A JIT compiler could use this to allow classes to be
+ * compiled the first time that they are looked up.  If the class is already
+ * registered with the runtime, this will not be called, so it can not be used
+ * for lazy loading of categories.
+ */
+OBJC_HOOK Class (*_objc_lookup_class)(const char *name);
+/**
+ * Class load callback.  
+ */
+OBJC_HOOK void (*_objc_load_callback)(Class cls, struct objc_category *category);
+/**
+ * The hook used for fast proxy lookups.  This takes an object and a selector
+ * and returns the instance that the message should be forwarded to.
+ */
+extern id (*objc_proxy_lookup)(id receiver, SEL op);
+/**
+ * New runtime forwarding hook.  This might be removed in future - it's
+ * actually no more expressive than the forward2 hook and forces Foundation to
+ * do some stuff that the runtime is better suited to.
+ */
+extern struct objc_slot *(*__objc_msg_forward3)(id, SEL);
+/**
+ * Forwarding hook.  Takes an object and a selector and returns a method that
+ * handles the forwarding.
+ */
+OBJC_HOOK IMP (*__objc_msg_forward2)(id, SEL);
+/**
+ * Hook defined for handling unhandled exceptions.  If the unwind library
+ * reaches the end of the stack without finding a handler then this hook is
+ * called.
+ */
+OBJC_HOOK void (*_objc_unexpected_exception)(id exception);
+/**
+ * Hook defined to return the class to be used for boxing a foreign exception
+ * type.  The class must implement:
+ *
+ * + (id)exceptionWithForeignException: (_Unwind_Exception*)ex;
+ *
+ * This will return an instance of the class that encapsulates the exception.
+ *
+ * Note: Due to limitations of the current ABI, there is no way for the handler
+ * to 
+ */
+OBJC_HOOK Class (*_objc_class_for_boxing_foreign_exception)(int64_t exceptionClass);
+
+/**
+ * Hook called when selector type does not match the method type in the
+ * receiver.  This should return the slot to use instead, although it may throw
+ * an exception or perform some other action.
+ */
+extern struct objc_slot* (*_objc_selector_type_mismatch)(Class cls, 
+       SEL selector, struct objc_slot *result);
+
+/**
+ * Returns the object if it is not currently in the process of being
+ * deallocated.  Returns nil otherwise.  
+ *
+ * This hook must be set for weak references to work with automatic reference counting.
+ */
+OBJC_HOOK id (*_objc_weak_load)(id object);
diff --git a/third_party/libobjc/objc/objc-api.h b/third_party/libobjc/objc/objc-api.h
new file mode 100644
index 0000000000000000000000000000000000000000..9786447367c1e22ff6c064c4258b874f3eb17baa
--- /dev/null
+++ b/third_party/libobjc/objc/objc-api.h
@@ -0,0 +1 @@
+#include <objc/runtime.h>
diff --git a/third_party/libobjc/objc/objc-arc.h b/third_party/libobjc/objc/objc-arc.h
new file mode 100644
index 0000000000000000000000000000000000000000..c7a420038de85d04c69be51d298bd883c41eb668
--- /dev/null
+++ b/third_party/libobjc/objc/objc-arc.h
@@ -0,0 +1,106 @@
+#ifndef __OBJC_ARC_INCLUDED__
+#define __OBJC_ARC_INCLUDED__
+/**
+ * Autoreleases the argument.  Equivalent to [obj autorelease].
+ */
+id objc_autorelease(id obj);
+/**
+ * Autoreleases a return value.  This is equivalent to [obj autorelease], but
+ * may also store the object somewhere where it can be quickly removed without
+ * the need for any message sending.
+ */
+id objc_autoreleaseReturnValue(id obj);
+/**
+ * Initializes object as a weak pointer and stores value in it, or nil if value
+ * has already begun deallocation.
+ */
+id objc_initWeak(id *object, id value);
+/**
+ * Loads the object.  Returns nil if the object stored at this address has
+ * already begun deallocation.
+ */
+id objc_loadWeak(id* object);
+/**
+ * Loads a weak value and retains it.
+ */
+id objc_loadWeakRetained(id* obj);
+/**
+ * Retains the argument.  Equivalent to [obj retain].
+ */
+id objc_retain(id obj);
+/**
+ * Retains and autoreleases an object.  Equivalent to [[obj retain] autorelease].
+ */
+id objc_retainAutorelease(id obj);
+/**
+ * Retains and releases a return value.  Equivalent to
+ * objc_retain(objc_autoreleaseReturnValue(obj)).
+ */
+id objc_retainAutoreleaseReturnValue(id obj);
+/**
+ * Retains a return value that has previously been autoreleased and returned.
+ * This is equivalent to objc_retainAutoreleaseReturnValue(), but may support a
+ * fast path, skipping the autorelease pool entirely.
+ */
+id objc_retainAutoreleasedReturnValue(id obj);
+/**
+ * Retains a block.
+ */
+id objc_retainBlock(id b);
+/**
+ * Stores value in addr.  This first retains value, then releases the old value
+ * at addr, and stores the retained value in the address.
+ */
+id objc_storeStrong(id *addr, id value);
+/**
+ * Stores obj in zeroing weak pointer addr.  If obj has begun deallocation,
+ * then this stores nil.
+ */
+id objc_storeWeak(id *addr, id obj);
+/**
+ * Allocates an autorelease pool and pushes it onto the top of the autorelease
+ * pool stack.  Note that the returned autorelease pool is not required to be
+ * an object.
+ */
+void *objc_autoreleasePoolPush(void);
+/**
+ * Pops the specified autorelease pool from the stack, sending release messages
+ * to every object that has been autreleased since the pool was created.
+ */
+void objc_autoreleasePoolPop(void *pool);
+/**
+ * Initializes dest as a weak pointer and stores the value stored in src into
+ * it.  
+ */
+void objc_copyWeak(id *dest, id *src);
+/**
+ * Destroys addr as a weak pointer.
+ */
+void objc_destroyWeak(id* addr);
+/**
+ * Equivalent to objc_copyWeak(), but may also set src to nil.
+ */
+void objc_moveWeak(id *dest, id *src);
+/**
+ * Releases an object.  Equivalent to [obj release].
+ */
+void objc_release(id obj);
+/**
+ * Mark the object as about to begin deallocation.  All subsequent reads of
+ * weak pointers will return 0.  This function should be called in -release,
+ * before calling [self dealloc].
+ *
+ * Nonstandard extension.
+ */
+void objc_delete_weak_refs(id obj);
+/**
+ * Returns the total number of objects in the ARC-managed autorelease pool.
+ */
+unsigned long objc_arc_autorelease_count_np(void);
+/**
+ * Returns the total number of times that an object has been autoreleased in
+ * this thread.
+ */
+unsigned long objc_arc_autorelease_count_for_object_np(id);
+#endif // __OBJC_ARC_INCLUDED__
+
diff --git a/third_party/libobjc/objc/objc-auto.h b/third_party/libobjc/objc/objc-auto.h
new file mode 100644
index 0000000000000000000000000000000000000000..2ec4939574fc6108b7051e353e7f74ee4a9f6b3f
--- /dev/null
+++ b/third_party/libobjc/objc/objc-auto.h
@@ -0,0 +1,255 @@
+/**
+ * objc-auto.h - This file provides the interface for Objective-C garbage
+ * collection
+ */
+
+/**
+ * Flags passed to objc_collect.  The low 2 bits specify the type of collection
+ * to perform, the remainder provide additional options.
+ */
+enum
+{
+	/**
+	 * Perform an incremental collection if the collection ratio has not been
+	 * exceeded, or a full collection if it has.
+	 */
+	OBJC_RATIO_COLLECTION        = 0,
+	/**
+	 * Performs an incremental collection. 
+	 */
+	OBJC_GENERATIONAL_COLLECTION = 1,
+	/**
+	 * Performs a full collection.
+	 */
+	OBJC_FULL_COLLECTION         = 2,
+	/**
+	 * Repeatedly performs a full collection until collection does not find any
+	 * new free memory.
+	 */
+	OBJC_EXHAUSTIVE_COLLECTION   = 3,
+	/**
+	 * Only runs the collector (in any mode) if the number of bytes allocated
+	 * since the last collection is greater than the threshold.
+	 */
+	OBJC_COLLECT_IF_NEEDED       = (1 << 3),
+	/**
+	 * Does not return until the collector has finished running.  
+	 */
+	OBJC_WAIT_UNTIL_DONE         = (1 << 4),
+};
+
+/**
+ * Options for objc_clear_stack().
+ */
+enum
+{
+	/** Ignored - provided for OS X compatibility. */
+	OBJC_CLEAR_RESIDENT_STACK = 1
+};
+
+
+/**
+ * Instructs the garbage collector to run.
+ */
+void objc_collect(unsigned long options);
+
+/**
+ * Returns yes if the connector is currently running, i.e. if every call to
+ * objc_gc_disable() has been balanced with a corresponding call to
+ * objc_gc_enable().
+ */
+BOOL objc_collectingEnabled(void);
+
+/**
+ * Returns YES if running in GC mode, NO otherwise.
+ */
+BOOL objc_collecting_enabled(void);
+
+/**
+ * Starts concurrent collection.  If this has been called, then finalizers will
+ * run in a separate thread.
+ */
+void objc_startCollectorThread(void);
+
+/**
+ * Causes all finalizers for instances of the specified class to be run on the
+ * main thread.  This is currently unimplemented.
+ */
+void objc_finalizeOnMainThread(Class cls);
+
+/**
+ * Attempts to delete pointers currently stored on unused bits of the stack.  
+ */
+void objc_clear_stack(unsigned long options);
+
+/**
+ * Returns YES if an object has been finalized.  
+ */
+BOOL objc_is_finalized(void *ptr);
+
+/**
+ * Performs an atomic compare and exchange on a pointer value.  Sets the value
+ * at objectLocation to replacement, if the current value is predicate.
+ */
+BOOL objc_atomicCompareAndSwapPtr(id predicate,
+                                  id replacement,
+                                  volatile id *objectLocation);
+/**
+ * Performs an atomic compare and exchange on a pointer value.  Sets the value
+ * at objectLocation to replacement, if the current value is predicate.
+ */
+BOOL objc_atomicCompareAndSwapPtrBarrier(id predicate,
+                                         id replacement,
+                                         volatile id *objectLocation);
+
+/**
+ * Performs an atomic compare and exchange on a pointer value.  Sets the value
+ * at objectLocation to replacement, if the current value is predicate.
+ */
+BOOL objc_atomicCompareAndSwapGlobal(id predicate,
+                                     id replacement,
+                                     volatile id *objectLocation);
+/**
+ * Performs an atomic compare and exchange on a pointer value.  Sets the value
+ * at objectLocation to replacement, if the current value is predicate.
+ */
+BOOL objc_atomicCompareAndSwapGlobalBarrier(id predicate,
+                                            id replacement,
+                                            volatile id *objectLocation);
+/**
+ * Performs an atomic compare and exchange on a pointer value.  Sets the value
+ * at objectLocation to replacement, if the current value is predicate.
+ */
+BOOL objc_atomicCompareAndSwapInstanceVariable(id predicate,
+                                               id replacement,
+                                               volatile id *objectLocation);
+/**
+ * Performs an atomic compare and exchange on a pointer value.  Sets the value
+ * at objectLocation to replacement, if the current value is predicate.
+ */
+BOOL objc_atomicCompareAndSwapInstanceVariableBarrier(id predicate,
+                                                      id replacement,
+                                                      volatile id *objectLocation);
+
+////////////////////////////////////////////////////////////////////////////////
+// The next group of functions are intended to be called automatically by the
+// compiler.  Normal user code will not call them.
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Performs a strong assignment.  Stores val in *ptr, ensuring that the
+ * assignment is visible to the collector.
+ */
+id objc_assign_strongCast(id val, id *ptr);
+
+/**
+ * Assigns val to the global pointed to by ptr, ensuring that the assignment is
+ * visible to the collector.
+ */
+id objc_assign_global(id val, id *ptr);
+/**
+ * Assigns val to the instance variable offset bytes from dest.
+ */
+id objc_assign_ivar(id val, id dest, ptrdiff_t offset);
+/**
+ * Performs a memmove() operation, ensuring that the copied bytes are always
+ * visible to the collector.
+ */
+void *objc_memmove_collectable(void *dst, const void *src, size_t size);
+/**
+ * Reads a weak pointer value.  All reads of pointers declared __weak MUST be
+ * via this call.
+ */
+id objc_read_weak(id *location);
+/**
+ * Assigns a value to location, which MUST have been declared __weak.  All
+ * assignments to weak pointers must go via this function.
+ */
+id objc_assign_weak(id value, id *location);
+
+
+/**
+ * Registers the current thread with the garbage collector.  Should be done as
+ * soon as a thread is created.  Until this is called, the thread's stack will
+ * be invisible to the collector.
+ */
+void objc_registerThreadWithCollector(void);
+/**
+ * Unregisters the current thread.  The thread's stack becomes invisible to the
+ * collector.  This should be called just before the thread exits.
+ */
+void objc_unregisterThreadWithCollector(void);
+/**
+ * Registers the current thread with the garbage collector and aborts if the
+ * registration failed.  The thread is expected to have already been
+ * registered.  This will print a warning message if it has not been.
+ */
+void objc_assertRegisteredThreadWithCollector();
+
+////////////////////////////////////////////////////////////////////////////////
+// Functions below this line are extensions to the OS X GC API, intended to
+// allow implementation of the higher-level public APIs
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Disables the garbage collector until it is reenabled with objc_gc_enable.
+ */
+void objc_gc_disable(void);
+/**
+ * Enables the garbage collector, if it has been previously disabled with a
+ * call to objc_gc_disable().  These calls store an internal count.  If
+ * objc_gc_disable() is called twice, then collection will not resume until
+ * objc_gc_enable() has also been called twice.
+ */
+void objc_gc_enable(void);
+
+/**
+ * Increments the reference count of objects.  This is intended to be used to
+ * implement CFRetain().  Reference counts should only be used when storing
+ * pointers to objects in untracked allocations (e.g. malloc() memory).
+ *
+ * This function is intended to be used to implement CFRetain().
+ */
+id objc_gc_retain(id object);
+/**
+ * Decrements the reference count on an object.  An object becomes eligible for
+ * automatic collection when its reference count reaches zero.  New objects
+ * have a reference count of zero, so they are eligible for collection as soon
+ * as the last pointer to them vanishes.
+ *
+ * This function is intended to be used to implement CFRelease().
+ */
+void objc_gc_release(id object);
+/**
+ * Returns the retain count of an object.  This is 0 for objects that have not
+ * had objc_gc_retain() called on them, which should be most objects in a
+ * garbage-collected program.
+ */
+int objc_gc_retain_count(id object);
+/**
+ * Allocates a buffer of memory, which will be automatically deallocated by the
+ * collector.  If isScanned is true, then this memory may contain pointers.  If
+ * not, then pointers stored in the returned region will be ignored.
+ *
+ * This function is intended to be used to implement NSAllocateCollectable().
+ */
+void* objc_gc_allocate_collectable(size_t size, BOOL isScanned);
+
+/**
+ * Reallocates a block of collectable memory.
+ */
+void* objc_gc_reallocate_collectable(void *ptr, size_t size, BOOL isScanned);
+
+/**
+ * If the pointer lies in a collectible memory region, returns the address at
+ * the start of this region.  Otherwise, returns NULL.
+ */
+void* objc_gc_collectable_address(void* ptr);
+
+/**
+ * Registers a class that should be copied on assignment to heap locations.
+ * For performance reasons, the runtime only permits a small number of classes
+ * to be registered.  These will always be copied when they are assigned, using
+ * the function specified in the second argument.
+ */
+BOOL objc_register_stack_class(Class cls, IMP copyFunction);
diff --git a/third_party/libobjc/objc/objc.h b/third_party/libobjc/objc/objc.h
new file mode 100644
index 0000000000000000000000000000000000000000..9786447367c1e22ff6c064c4258b874f3eb17baa
--- /dev/null
+++ b/third_party/libobjc/objc/objc.h
@@ -0,0 +1 @@
+#include <objc/runtime.h>
diff --git a/third_party/libobjc/objc/runtime-deprecated.h b/third_party/libobjc/objc/runtime-deprecated.h
new file mode 100644
index 0000000000000000000000000000000000000000..f85d3df27a2f56639c78a9067b313594175c8bd4
--- /dev/null
+++ b/third_party/libobjc/objc/runtime-deprecated.h
@@ -0,0 +1,78 @@
+#if !defined(__GNUSTEP_LIBOBJC_RUNTIME_DEPRECATED_INCLUDED__) && !defined(GNUSTEP_LIBOBJC_NO_LEGACY)
+#	define __GNUSTEP_LIBOBJC_RUNTIME_DEPRECATED_INCLUDED__
+
+/**
+ * Legacy GNU runtime compatibility.
+ *
+ * All of the functions in this section are deprecated and should not be used
+ * in new code.
+ */
+
+__attribute__((deprecated))
+void *objc_malloc(size_t size);
+
+__attribute__((deprecated))
+void *objc_atomic_malloc(size_t size);
+
+__attribute__((deprecated))
+void *objc_valloc(size_t size);
+
+__attribute__((deprecated))
+void *objc_realloc(void *mem, size_t size);
+
+__attribute__((deprecated))
+void * objc_calloc(size_t nelem, size_t size);
+
+__attribute__((deprecated))
+void objc_free(void *mem);
+
+__attribute__((deprecated))
+id objc_get_class(const char *name);
+
+__attribute__((deprecated))
+id objc_lookup_class(const char *name);
+
+__attribute__((deprecated))
+id objc_get_meta_class(const char *name);
+
+#if !defined(__OBJC_RUNTIME_INTERNAL__)
+__attribute__((deprecated))
+#endif
+Class objc_next_class(void **enum_state);
+
+__attribute__((deprecated))
+Class class_pose_as(Class impostor, Class super_class);
+
+__attribute__((deprecated))
+SEL sel_get_typed_uid (const char *name, const char *types);
+
+__attribute__((deprecated))
+SEL sel_get_any_typed_uid (const char *name);
+
+__attribute__((deprecated))
+SEL sel_get_any_uid (const char *name);
+
+__attribute__((deprecated))
+SEL sel_get_uid(const char *name);
+
+__attribute__((deprecated))
+const char *sel_get_name(SEL selector);
+
+#if !defined(__OBJC_RUNTIME_INTERNAL__)
+__attribute__((deprecated))
+#endif
+BOOL sel_is_mapped(SEL selector);
+
+__attribute__((deprecated))
+const char *sel_get_type(SEL selector);
+
+__attribute__((deprecated))
+SEL sel_register_name(const char *name);
+
+__attribute__((deprecated))
+SEL sel_register_typed_name(const char *name, const char *type);
+
+__attribute__((deprecated))
+BOOL sel_eq(SEL s1, SEL s2);
+
+#endif
diff --git a/third_party/libobjc/objc/runtime.h b/third_party/libobjc/objc/runtime.h
new file mode 100644
index 0000000000000000000000000000000000000000..86c67ed5a2e1debe4246f2edc5286499d366f84f
--- /dev/null
+++ b/third_party/libobjc/objc/runtime.h
@@ -0,0 +1,1040 @@
+#ifndef __LIBOBJC_RUNTIME_H_INCLUDED__
+#define __LIBOBJC_RUNTIME_H_INCLUDED__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef __GNUSTEP_RUNTIME__
+#	define __GNUSTEP_RUNTIME__
+#endif
+
+#ifndef __has_feature
+#	define __has_feature(x) 0
+#endif
+
+#ifndef __unsafe_unretained
+#	ifndef __has_feature
+#		define __unsafe_unretained
+#	elif !__has_feature(objc_arc)
+#		define __unsafe_unretained
+#	endif
+#endif
+
+// Make sure we get the limit macros, even in C++ mode
+#ifndef __STDC_LIMIT_MACROS                                                     
+#	define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <stdint.h>
+#include <limits.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include "Availability.h"
+
+// Undo GNUstep substitutions
+#ifdef class_setVersion
+#	undef class_setVersion
+#endif
+#ifdef class_getClassMethod
+#	undef class_getClassMethod
+#endif
+#ifdef objc_getClass
+#	undef objc_getClass
+#endif
+#ifdef objc_lookUpClass
+#	undef objc_lookUpClass
+#endif
+
+/**
+ * Opaque type for Objective-C instance variable metadata.
+ */
+typedef struct objc_ivar* Ivar;
+
+// Don't redefine these types if the old GCC header was included first.
+#ifndef __objc_INCLUDE_GNU
+// Define the macro so that including the old GCC header does nothing.
+#	define __objc_INCLUDE_GNU
+#	define __objc_api_INCLUDE_GNU
+
+
+/**
+ * Opaque type used for selectors.
+ */
+#if !defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__)
+typedef const struct objc_selector *SEL;
+#else
+typedef struct objc_selector *SEL;
+#endif
+
+/**
+ * Opaque type for Objective-C classes.
+ */
+typedef struct objc_class *Class;
+
+/**
+ * Type for Objective-C objects.
+ */
+typedef struct objc_object
+{
+	/**
+	 * Pointer to this object's class.  Accessing this directly is STRONGLY
+	 * discouraged.  You are recommended to use object_getClass() instead.
+	 */
+#ifndef __OBJC_RUNTIME_INTERNAL__
+	__attribute__((deprecated))
+#endif
+	Class isa;
+} *id;
+
+/**
+ * Structure used for calling superclass methods.
+ */
+struct objc_super
+{
+	/** The receiver of the message. */
+	__unsafe_unretained id receiver;
+	/** The class containing the method to call. */
+#	if !defined(__cplusplus)  &&  !__OBJC2__
+	Class class;
+#	else
+	Class super_class;
+#	endif
+};
+
+/**
+ * Instance Method Pointer type.  Note: Since the calling convention for
+ * variadic functions sometimes differs from the calling convention for
+ * non-variadic functions, you must cast an IMP to the correct type before
+ * calling.
+ */
+typedef id (*IMP)(id, SEL, ...);
+/**
+ * Opaque type for Objective-C method metadata.
+ */
+typedef struct objc_method *Method;
+
+/**
+ * Objective-C boolean type.
+ */
+#	ifdef STRICT_APPLE_COMPATIBILITY
+typedef signed char BOOL;
+#	else
+#		ifdef __vxwords
+typedef  int BOOL;
+#		else
+typedef unsigned char BOOL;
+#		endif
+#	endif
+
+#else
+// Method in the GCC runtime is a struct, Method_t is the pointer
+#	define Method Method_t
+#endif // __objc_INCLUDE_GNU
+
+
+/**
+ * Opaque type for Objective-C property metadata.
+ */
+typedef struct objc_property* objc_property_t;
+/**
+ * Opaque type for Objective-C protocols.  Note that, although protocols are
+ * objects, sending messages to them is deprecated in Objective-C 2 and may not
+ * work in the future.
+ */
+#ifdef __OBJC__
+@class Protocol;
+#else
+typedef struct objc_protocol Protocol;
+#endif
+
+/**
+ * Objective-C method description.
+ */
+struct objc_method_description
+{
+	/**
+	 * The name of this method.
+	 */
+	SEL   name;
+	/**
+	 * The types of this method.
+	 */
+	const char *types;
+};
+
+/**
+ * The objc_property_attribute_t type is used to store attributes for
+ * properties.  This is used to store a decomposed version of the property
+ * encoding, with each flag stored in the name and each value in the value.
+ *
+ * All of the strings that these refer to are internal to the runtime and
+ * should not be freed.
+ */
+typedef struct
+{
+	/**
+	 * The flag that this attribute describes.  All current flags are single characters,
+	 */
+	const char *name;
+	/**
+	 */
+	const char *value;
+} objc_property_attribute_t;
+
+
+
+#ifndef YES
+#	define YES ((BOOL)1)
+#endif
+#ifndef NO
+#	define NO ((BOOL)0)
+#endif
+
+#ifdef __GNUC
+#	define _OBJC_NULL_PTR __null
+#elif defined(__cplusplus)
+#	define _OBJC_NULL_PTR 0
+#else
+#	define _OBJC_NULL_PTR ((void*)0)
+#endif
+
+#ifndef nil
+#	define nil ((id)_OBJC_NULL_PTR)
+#endif
+
+#ifndef Nil
+#	define Nil ((Class)_OBJC_NULL_PTR)
+#endif
+
+#include "slot.h"
+
+/**
+ * Adds an instance variable to the named class.  The class must not have been
+ * registered by the runtime.  The alignment must be the base-2 logarithm of
+ * the alignment requirement and the types should be an Objective-C type encoding.
+ */
+BOOL class_addIvar(Class cls,
+                   const char *name,
+                   size_t size,
+                   uint8_t alignment,
+                   const char *types);
+
+/**
+ * Adds a method to the class.
+ */
+BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types);
+
+/**
+ * Adds a protocol to the class.
+ */
+BOOL class_addProtocol(Class cls, Protocol *protocol);
+
+/**
+ * Tests for protocol conformance.  Note: Currently, protocols with the same
+ * name are regarded as equivalent, even if they have different methods.  This
+ * behaviour will change in a future version.
+ */
+BOOL class_conformsToProtocol(Class cls, Protocol *protocol);
+
+/**
+ * Copies the instance variable list for this class.  The integer pointed to by
+ * the outCount argument is set to the number of instance variables returned.
+ * The caller is responsible for freeing the returned buffer.
+ */
+Ivar* class_copyIvarList(Class cls, unsigned int *outCount);
+
+/**
+ * Copies the method list for this class.  The integer pointed to by the
+ * outCount argument is set to the number of methods returned.  The caller is
+ * responsible for freeing the returned buffer.
+ */
+Method * class_copyMethodList(Class cls, unsigned int *outCount);
+
+/**
+ * Copies the declared property list for this class.  The integer pointed to by
+ * the outCount argument is set to the number of declared properties returned.
+ * The caller is responsible for freeing the returned buffer.
+ */
+objc_property_t* class_copyPropertyList(Class cls, unsigned int *outCount);
+
+/**
+ * Copies the protocol list for this class.  The integer pointed to by the
+ * outCount argument is set to the number of protocols returned.  The caller is
+ * responsible for freeing the returned buffer.
+ */
+Protocol *__unsafe_unretained* class_copyProtocolList(Class cls, unsigned int *outCount);
+
+/**
+ * Creates an instance of this class, allocating memory using malloc.
+ */
+id class_createInstance(Class cls, size_t extraBytes);
+
+/**
+ * Returns a pointer to the method metadata for the specified method in this
+ * class.  This is an opaque data type and must be accessed with the method_*()
+ * family of functions.
+ */
+Method class_getClassMethod(Class aClass, SEL aSelector);
+
+/**
+ * Returns a pointer to the  metadata for the specified class variable in
+ * this class.  This is an opaque data type and must be accessed with the
+ * ivar_*() family of functions.
+ */
+Ivar class_getClassVariable(Class cls, const char* name);
+
+/**
+ * Returns a pointer to the method metadata for the specified instance method
+ * in this class.  This is an opaque data type and must be accessed with the
+ * method_*() family of functions.
+ */
+Method class_getInstanceMethod(Class aClass, SEL aSelector);
+
+/**
+ * Returns the size of an instance of the named class, in bytes.  All of the
+ * class's superclasses must be loaded before this call, or the result is
+ * undefined with the non-fragile ABI.
+ */
+size_t class_getInstanceSize(Class cls);
+
+/**
+ * Look up the named instance variable in the class (and its superclasses)
+ * returning a pointer to the instance variable definition or a null
+ * pointer if no instance variable of that name was found.
+ */
+Ivar class_getInstanceVariable(Class cls, const char* name);
+
+/**
+ * Sets the object value of a specified instance variable.
+ */
+void object_setIvar(id object, Ivar ivar, id value);
+/**
+ * Sets a named instance variable to the value specified by *value.  Note that
+ * the instance variable must be a pointer-sized quantity.
+ */
+Ivar object_setInstanceVariable(id obj, const char *name, void *value);
+
+/**
+ * Returns the value of the named instance variable.  This should not be used
+ * with instance variables that are not pointers.
+ */
+id object_getIvar(id object, Ivar ivar);
+
+/**
+ * Returns a named instance variable via the final parameter.  Note that
+ * calling object_getIvar() on the value returned from this function is faster.
+ *
+ * Note that the instance variable must be a pointer-sized quantity.
+ */
+Ivar object_getInstanceVariable(id obj, const char *name, void **outValue);
+
+/**
+ * Returns a pointer to the function used to handle the specified message.  If
+ * the receiver does not have a method corresponding to this message then this
+ * function may return a runtime function that performs forwarding.
+ */
+IMP class_getMethodImplementation(Class cls, SEL name);
+
+/**
+ * Identical to class_getMethodImplementation().
+ */
+IMP class_getMethodImplementation_stret(Class cls, SEL name);
+
+/**
+ * Returns the name of the class.  This string is owned by the runtime and is
+ * valid for (at least) as long as the class remains loaded.
+ */
+const char * class_getName(Class cls);
+
+/**
+ * Retrieves metadata about the property with the specified name.
+ */
+objc_property_t class_getProperty(Class cls, const char *name);
+
+/**
+ * Returns the superclass of the specified class.
+ */
+Class class_getSuperclass(Class cls);
+
+/**
+ * Returns the version of the class.  Currently, the class version is not used
+ * inside the runtime at all, however it may be used for the developer-mode ABI.
+ */
+int class_getVersion(Class theClass);
+
+/**
+ * Sets the version for this class.
+ */
+void class_setVersion(Class theClass, int version);
+
+OBJC_GNUSTEP_RUNTIME_UNSUPPORTED("Weak instance variables")
+const char *class_getWeakIvarLayout(Class cls);
+
+/**
+ * Returns whether the class is a metaclass.  This can be used in conjunction
+ * with object_getClass() for differentiating between objects and classes.
+ */
+BOOL class_isMetaClass(Class cls);
+
+/**
+ * Registers an alias for the class. Returns YES if the alias could be
+ * registered successfully.
+ */
+OBJC_NONPORTABLE
+BOOL class_registerAlias_np(Class cls, const char *alias);
+
+/**
+ * Replaces the named method with a new implementation.  Note: the GNUstep
+ * Objective-C runtime uses typed selectors, however the types of the selector
+ * will be ignored and a new selector registered with the specified types.
+ */
+IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types);
+
+/**
+ * Returns YES if instances of this class has a method that implements the
+ * specified message, NO otherwise.  If the class handles this message via one
+ * or more of the various forwarding mechanisms, then this will still return
+ * NO.
+ */
+BOOL class_respondsToSelector(Class cls, SEL sel);
+
+/**
+ * Returns the instance variable layout of this class as an opaque list that
+ * can be applied to other classes.
+ */
+const char *class_getIvarLayout(Class cls);
+/**
+ * Sets the class's instance variable layout.  The layout argument must be a
+ * value returned by class_getIvarLayout().
+ */
+void class_setIvarLayout(Class cls, const char *layout);
+
+/**
+ * Sets the superclass of the specified class.  This function is deprecated,
+ * because modifying the superclass of a class at run time is a very complex
+ * operation and this function is almost always used incorrectly.
+ */
+__attribute__((deprecated))
+Class class_setSuperclass(Class cls, Class newSuper);
+
+OBJC_GNUSTEP_RUNTIME_UNSUPPORTED("Weak instance variables")
+void class_setWeakIvarLayout(Class cls, const char *layout);
+
+/**
+ * Returns the name of an instance variable.
+ */
+const char* ivar_getName(Ivar ivar);
+
+/**
+ * Returns the offset of an instance variable.  This value can be added to the
+ * object pointer to get the address of the instance variable.
+ */
+ptrdiff_t ivar_getOffset(Ivar ivar);
+
+/**
+ * Returns the Objective-C type encoding of the instance variable.
+ */
+const char* ivar_getTypeEncoding(Ivar ivar);
+
+/**
+ * Copies the type encoding of an argument of this method.  The caller is
+ * responsible for freeing the returned C string.  Arguments 0 and 1 of any
+ * Objective-C method will be the self and _cmd parameters, so the returned
+ * value will be "@" and ":" respectively.
+ */
+char* method_copyArgumentType(Method method, unsigned int index);
+
+/**
+ * Copies the type encoding of an argument of this method.  The caller is
+ * responsible for freeing the returned C string.
+ */
+char* method_copyReturnType(Method method);
+
+/**
+ * Exchanges the implementations of the two methods.  Note: this call is very
+ * expensive on the GNUstep runtime and its use is discouraged.  It is
+ * recommended that users call class_replaceMethod() instead.
+ */
+void method_exchangeImplementations(Method m1, Method m2);
+
+/**
+ * Copies the Objective-C type encoding of a specified method parameter into a
+ * buffer provided by the caller.  This method does not provide any means for
+ * the caller to easily detect truncation, and will only NULL-terminate the
+ * output string if there is enough space for the argument type and the NULL
+ * terminator.  Its use is therefore discouraged.
+ */
+void method_getArgumentType(Method method, unsigned int index, char *dst, size_t dst_len);
+
+/**
+ * Returns a pointer to the function used to implement this method.
+ */
+IMP method_getImplementation(Method method);
+
+/**
+ * Returns the selector used to identify this method.  Note that, unlike the
+ * Apple runtimes, the GNUstep runtime uses typed selectors, so the return
+ * value for this also identifies the type of the method, not just its name,
+ * although calling method_getTypeEncoding() is faster if you just require the
+ * types.
+ */
+SEL method_getName(Method method);
+
+/**
+ * Returns the number of arguments (including self and _cmd) that this method
+ * expects.
+ */
+unsigned method_getNumberOfArguments(Method method);
+
+/**
+ * Copies the Objective-C type encoding of a method's return value into a
+ * buffer provided by the caller.  This method does not provide any means for
+ * the caller to easily detect truncation, and will only NULL-terminate the
+ * output string if there is enough space for the argument type and the NULL
+ * terminator.  Its use is therefore discouraged.
+ */
+void method_getReturnType(Method method, char *dst, size_t dst_len);
+
+/**
+ * Returns the type encoding for the method.  This string is owned by the
+ * runtime and will persist for (at least) as long as the class owning the
+ * method is loaded.
+ */
+const char * method_getTypeEncoding(Method method);
+
+/**
+ * Sets the function used to implement this method.  This function is very
+ * expensive with the GNUstep runtime and its use is discouraged.  It is
+ * recommended that you call class_replaceMethod() instead.
+ */
+IMP method_setImplementation(Method method, IMP imp);
+
+/**
+ * Allocates a new class and metaclass inheriting from the specified class,
+ * with some space after the class for storing extra data.  This space can be
+ * used for class variables by adding instance variables to the returned
+ * metaclass.
+ */
+Class objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes);
+
+/**
+ * Frees a class and metaclass allocated with objc_allocateClassPair().  Any
+ * attempts to send messages to instances of this class or its subclasses
+ * result in undefined behaviour.
+ */
+void objc_disposeClassPair(Class cls);
+
+/**
+ * Returns the class with the specified name, if one has been registered with
+ * the runtime, or nil if one does not exist.  If no class of this name is
+ * loaded, it calls the _objc_lookup_class() callback to allow an external
+ * library to load the module providing this class.
+ */
+id objc_getClass(const char *name);
+
+/**
+ * Copies all of the classes currently registered with the runtime into the
+ * buffer specified as the first argument.  If the buffer is NULL or its length
+ * is 0, it returns the total number of classes registered with the runtime.
+ * Otherwise, it copies classes and returns the number copied.
+ */
+int objc_getClassList(Class *buffer, int bufferLen);
+/**
+ * Returns a copy of the list of all classes in the system.  The caller is
+ * responsible for freeing this list.  The number of classes is returned in the
+ * parameter.
+ */
+Class *objc_copyClassList(unsigned int *outCount);
+
+/**
+ * Returns the metaclass with the specified name.  This is equivalent to
+ * calling object_getClass() on the result of objc_getClass().
+ */
+id objc_getMetaClass(const char *name);
+
+/**
+ * Returns the class with the specified name, aborting if none is found.  This
+ * function should generally only be called early on in a program, to ensure
+ * that all required libraries are loaded.
+ */
+id objc_getRequiredClass(const char *name);
+
+/**
+ * Looks up the class with the specified name, but does not invoke any
+ * external lazy loading mechanisms.
+ */
+id objc_lookUpClass(const char *name);
+
+/**
+ * Returns the protocol with the specified name.
+ */
+Protocol *objc_getProtocol(const char *name);
+/**
+ * Allocates a new protocol.  This returns NULL if a protocol with the same
+ * name already exists in the system.
+ *
+ * Protocols are immutable after they have been registered, so may only be
+ * modified between calling this function and calling objc_registerProtocol().
+ */
+Protocol *objc_allocateProtocol(const char *name);
+/**
+ * Registers a protocol with the runtime.  After this point, the protocol may
+ * not be modified.
+ */
+void objc_registerProtocol(Protocol *proto);
+/**
+ * Adds a method to the protocol.
+ */
+void protocol_addMethodDescription(Protocol *aProtocol,
+                                   SEL name,
+                                   const char *types,
+                                   BOOL isRequiredMethod,
+                                   BOOL isInstanceMethod);
+/**
+ * Adds a protocol to the protocol.
+ */
+void protocol_addProtocol(Protocol *aProtocol, Protocol *addition);
+/**
+ * Adds a property to the protocol.
+ */
+void protocol_addProperty(Protocol *aProtocol,
+                          const char *name,
+                          const objc_property_attribute_t *attributes,
+                          unsigned int attributeCount,
+                          BOOL isRequiredProperty,
+                          BOOL isInstanceProperty);
+
+
+/**
+ * Registers a new class and its metaclass with the runtime.  This function
+ * should be called after allocating a class with objc_allocateClassPair() and
+ * adding instance variables and methods to it.  A class can not have instance
+ * variables added to it after objc_registerClassPair() has been called.
+ */
+void objc_registerClassPair(Class cls);
+
+/**
+ * Returns a pointer immediately after the instance variables declared in an
+ * object.  This is a pointer to the storage specified with the extraBytes
+ * parameter given when allocating an object.
+ */
+void *object_getIndexedIvars(id obj);
+
+// FIXME: The GNU runtime has a version of this which omits the size parameter
+//id object_copy(id obj, size_t size);
+
+/**
+ * Free an object created with class_createInstance().
+ */
+id object_dispose(id obj);
+
+/**
+ * Returns the class of the object.  Note: the isa pointer should not be
+ * accessed directly with the GNUstep runtime.
+ */
+Class object_getClass(id obj);
+
+/**
+ * Sets the class of the object.  Note: the isa pointer should not be
+ * accessed directly with the GNUstep runtime.
+ */
+Class object_setClass(id obj, Class cls);
+
+/**
+ * Returns the name of the class of the object.  This is equivalent to calling
+ * class_getName() on the result of object_getClass().
+ */
+const char *object_getClassName(id obj);
+
+
+/**
+ * Returns the name of a specified property.
+ */
+const char *property_getName(objc_property_t property);
+
+/**
+ * Returns the attributes for the specified property.  This is similar to an
+ * Objective-C type encoding, but contains some extra information.  A full
+ * description of the format for this string may be found in Apple's
+ * Objective-C Runtime Programming Guide.
+ */
+const char *property_getAttributes(objc_property_t property);
+
+/**
+ * Returns an array of attributes for this property.
+ */
+objc_property_attribute_t *property_copyAttributeList(objc_property_t property,
+                                                      unsigned int *outCount);
+/**
+ * Adds a property to the class, given a specified set of attributes.  Note
+ * that this only sets the property metadata.  The property accessor methods
+ * must already be created.
+ */
+BOOL class_addProperty(Class cls,
+                       const char *name,
+                       const objc_property_attribute_t *attributes, 
+                       unsigned int attributeCount);
+
+/**
+ * Replaces property metadata.  If the property does not exist, then this is
+ * equivalent to calling class_addProperty().
+ */
+void class_replaceProperty(Class cls,
+                           const char *name,
+                           const objc_property_attribute_t *attributes,
+                           unsigned int attributeCount);
+
+/**
+ * Returns a copy of a single attribute.
+ */
+char *property_copyAttributeValue(objc_property_t property,
+                                  const char *attributeName);
+
+/**
+ * Testswhether a protocol conforms to another protocol.
+ */
+BOOL protocol_conformsToProtocol(Protocol *p, Protocol *other);
+
+/**
+ * Returns an array of method descriptions.  Stores the number of elements in
+ * the array in the variable pointed to by the last parameter.  The caller is
+ * responsible for freeing this array.
+ */
+struct objc_method_description *protocol_copyMethodDescriptionList(Protocol *p,
+	BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *count);
+
+/**
+ * Returns an array of property metadata values, with the number being stored
+ * in the variable pointed to by the last argument.  The caller is responsible
+ * for freeing the returned array.
+ */
+objc_property_t *protocol_copyPropertyList(Protocol *p, unsigned int *count);
+
+/**
+ * Returns an array of protocols that this protocol conforms to, with the
+ * number of protocols in the array being returned via the last argument.  The
+ * caller is responsible for freeing this array.
+ */
+Protocol *__unsafe_unretained*protocol_copyProtocolList(Protocol *p, unsigned int *count);
+
+/**
+ * Returns all of the protocols that the runtime is aware of.  Note that
+ * protocols compiled by GCC and not attacked to classes may not have been
+ * registered with the runtime.  The number of protocols returned is stored at
+ * the address indicated by the pointer argument.
+ *
+ * The caller is responsible for freeing the returned array.
+ */
+Protocol *__unsafe_unretained*objc_copyProtocolList(unsigned int *outCount);
+/**
+ * Returns the method description for the specified method within a given
+ * protocol.
+ */
+struct objc_method_description protocol_getMethodDescription(Protocol *p,
+	SEL aSel, BOOL isRequiredMethod, BOOL isInstanceMethod);
+
+/**
+ * Returns the name of the specified protocol.
+ */
+const char* protocol_getName(Protocol *p);
+
+/**
+ * Returns the property metadata for the property with the specified name.
+ *
+ * Note: The Apple documentation for this method contains some nonsense for
+ * isInstanceProperty.  As there is no language syntax for defining properties
+ * on classes, we return NULL if this is not YES.
+ */
+objc_property_t protocol_getProperty(Protocol *p, const char *name,
+	BOOL isRequiredProperty, BOOL isInstanceProperty);
+
+/**
+ * Compares two protocols.  Currently, protocols are assumed to be equal if
+ * their names match.  This is required for compatibility with the GCC ABI,
+ * which made not attempt to unique protocols (or even register them with the
+ * runtime).
+ */
+BOOL protocol_isEqual(Protocol *p, Protocol *other);
+
+/**
+ * The message lookup function used by the GCC ABI.  This returns a pointer to
+ * the function (either a method or a forwarding hook) that should be called in
+ * response to a given message.
+ */
+IMP objc_msg_lookup(id, SEL) OBJC_NONPORTABLE;
+/**
+ * The message lookup function used for messages sent to super in the GCC ABI.
+ * This specifies both the class and the 
+ */
+IMP objc_msg_lookup_super(struct objc_super*, SEL) OBJC_NONPORTABLE;
+
+/**
+ * Returns the name of the specified selector.
+ */
+const char *sel_getName(SEL sel);
+
+/**
+ * Registers a selector with the runtime.  This is equivalent to sel_registerName().
+ */
+SEL sel_getUid(const char *selName);
+
+/**
+ * Returns whether two selectors are equal.  For the purpose of comparison,
+ * selectors with the same name and type are regarded as equal.  Selectors with
+ * the same name and different types are regarded as different.  If one
+ * selector is typed and the other is untyped, but the names are the same, then
+ * they are regarded as equal.  This means that sel_isEqual(a, b) and
+ * sel_isEqual(a, c) does not imply sel_isEqual(b, c) - if a is untyped but
+ * both b and c are typed selectors with different types, then then the first
+ * two will return YES, but the third case will return NO.
+ */
+BOOL sel_isEqual(SEL sel1, SEL sel2);
+
+/**
+ * Registers an untyped selector with the runtime.
+ */
+SEL sel_registerName(const char *selName);
+
+/**
+ * Register a typed selector.
+ */
+SEL sel_registerTypedName_np(const char *selName, const char *types) OBJC_NONPORTABLE;
+
+/**
+ * Returns the type encoding associated with a selector, or the empty string is
+ * there is no such type.
+ */
+const char *sel_getType_np(SEL aSel) OBJC_NONPORTABLE;
+
+/**
+ * Enumerates all of the type encodings associated with a given selector name
+ * (up to a specified limit).  This function returns the number of types that
+ * exist for a specific selector, but only copies up to count of them into the
+ * array passed as the types argument.  This allows you to call the function
+ * once with a relatively small on-stack buffer and then only call it again
+ * with a heap-allocated buffer if there is not enough space.
+ */
+unsigned sel_copyTypes_np(const char *selName, const char **types, unsigned count) OBJC_NONPORTABLE;
+
+/**
+ * Enumerates all of the type encodings associated with a given selector name
+ * (up to a specified limit).  This function returns the number of types that
+ * exist for a specific selector, but only copies up to count of them into the
+ * array passed as the types argument.  This allows you to call the function
+ * once with a relatively small on-stack buffer and then only call it again
+ * with a heap-allocated buffer if there is not enough space.
+ */
+unsigned sel_copyTypedSelectors_np(const char *selName, SEL *const sels, unsigned count) OBJC_NONPORTABLE;
+
+/**
+ * New ABI lookup function.  Receiver may be modified during lookup or proxy
+ * forwarding and the sender may affect how lookup occurs.
+ */
+extern struct objc_slot *objc_msg_lookup_sender(id *receiver, SEL selector, id sender)
+	OBJC_NONPORTABLE;
+
+/**
+ * Registers a class for small objects.  Small objects are stored inside a
+ * pointer.  If the class can be registered, then this returns YES.  The second
+ * argument specifies the bit pattern to use to identify the small object.
+ */
+BOOL objc_registerSmallObjectClass_np(Class cls, uintptr_t classId);
+
+/**
+ * The mask identifying the bits that can be used in an object pointer to
+ * identify a small object.  On 32-bit systems, we use the low bit.  On 64-bit
+ * systems, we use the low 3 bits.  In both cases, the lowest bit must be 1.
+ * This restriction may be relaxed in the future on 64-bit systems.
+ */
+#ifndef UINTPTR_MAX
+#	define OBJC_SMALL_OBJECT_MASK ((sizeof(void*) == 4) ? 1 : 7)
+#elif UINTPTR_MAX < UINT64_MAX
+#	define OBJC_SMALL_OBJECT_MASK 1
+#else
+#	define OBJC_SMALL_OBJECT_MASK 7
+#endif
+/**
+ * The number of bits reserved for the class identifier in a small object.
+ */
+#ifndef UINTPTR_MAX
+#	define OBJC_SMALL_OBJECT_SHIFT ((sizeof(void*) == 4) ? 1 : 3)
+#elif UINTPTR_MAX < UINT64_MAX
+#	define OBJC_SMALL_OBJECT_SHIFT 1
+#else
+#	define OBJC_SMALL_OBJECT_SHIFT 3
+#endif
+
+
+/**
+ * Valid values for objc_AssociationPolicy.  This is really a bitfield, but
+ * only specific combinations of flags are permitted.
+ */
+enum
+{
+	/**
+	 * Perform straight assignment, no message sends.
+	 */
+	OBJC_ASSOCIATION_ASSIGN = 0,
+	/**
+	 * Retain the associated object.
+	 */
+	OBJC_ASSOCIATION_RETAIN_NONATOMIC = 1,
+	/**
+	 * Copy the associated object, by sending it a -copy message.
+	 */
+	OBJC_ASSOCIATION_COPY_NONATOMIC = 3,
+	/**
+	 * Atomic retain.
+	 */
+	OBJC_ASSOCIATION_RETAIN = 0x301,
+	/**
+	 * Atomic copy.
+	 */
+	OBJC_ASSOCIATION_COPY = 0x303
+};
+/**
+ * Association policy, used when setting associated objects.  
+ */
+typedef uintptr_t objc_AssociationPolicy;
+
+/**
+ * Returns an object previously stored by calling objc_setAssociatedObject()
+ * with the same arguments, or nil if none exists.
+ */
+id objc_getAssociatedObject(id object, void *key);
+/**
+ * Associates an object with another.  This provides a mechanism for storing
+ * extra state with an object, beyond its declared instance variables.  The
+ * pointer used as a key is treated as an opaque value.  The best way of
+ * ensuring this is to pass the pointer to a static variable as the key.  The
+ * value may be any object, but must respond to -copy or -retain, and -release,
+ * if an association policy of copy or retain is passed as the final argument.
+ */
+void objc_setAssociatedObject(id object, void *key, id value, objc_AssociationPolicy policy);
+/**
+ * Removes all associations from an object.  
+ */
+void objc_removeAssociatedObjects(id object);
+
+/**
+ * Converts a block into an IMP that can be used as a method.  The block should
+ * take an object pointer (self) as its first argument, and then the same
+ * arguments as the method.
+ */
+IMP imp_implementationWithBlock(void *block);
+/**
+ * Returns the type encoding of an IMP that would be returned by passing the
+ * block to imp_implementationWithBlock().  Returns NULL if this is not a valid
+ * block encoding for transforming to an IMP (it must take id as its first
+ * argument).  The caller is responsible for freeing the returned value.
+ */
+char *block_copyIMPTypeEncoding_np(void*block);
+/**
+ * Returns the block that was used in an IMP created by
+ * imp_implementationWithBlock().  The result of calling this function with any
+ * other IMP is undefined.
+ */
+void *imp_getBlock(IMP anImp);
+/**
+ * Removes a block that was converted to an IMP with
+ * imp_implementationWithBlock().  The result of calling this function with any
+ * other IMP is undefined.  Returns YES on success, NO on failure.
+ */
+BOOL imp_removeBlock(IMP anImp);
+
+/**
+ * Adds a method to a specific object,  This method will not be added to any
+ * other instances of the same class.
+ */
+BOOL object_addMethod_np(id object, SEL name, IMP imp, const char *types);
+
+/**
+ * Replaces a method on a specific object,  This method will not be added to
+ * any other instances of the same class.
+ */
+IMP object_replaceMethod_np(id object, SEL name, IMP imp, const char *types);
+
+/**
+ * Creates a clone, in the JavaScript sense - an object which inherits both
+ * associated references and methods from the original object.
+ */
+id object_clone_np(id object);
+
+/**
+ * Returns the prototype of the object if it was created with
+ * object_clone_np(), or nil otherwise.
+ */
+id object_getPrototype_np(id object);
+
+/**
+ * Toggles whether Objective-C objects caught in C++ exception handlers in
+ * Objective-C++ mode should follow Objective-C or C++ semantics.  The obvious
+ * choice is for them to follow C++ semantics, because people using a C++
+ * language construct would intuitively expect them to have C++ semantics,
+ * where the catch behaviour depends on the static type of the thrown object,
+ * not its run-time type.
+ *
+ * Apple, therefore, chose the other option.
+ *
+ * We default to Apple-compatible mode, but can enable the sane behaviour if
+ * the user opts in.  Note that doing this when linking against third-party
+ * frameworks written in Objective-C++ 2 may cause weird problems if the expect
+ * the other behaviour.
+ *
+ * This currently sets a global value.  In the future, it may be configurable
+ * on a per-thread basis.
+ */
+int objc_set_apple_compatible_objcxx_exceptions(int newValue) OBJC_NONPORTABLE;
+
+
+#define _C_ID       '@'
+#define _C_CLASS    '#'
+#define _C_SEL      ':'
+#define _C_BOOL     'B'
+
+#define _C_CHR      'c'
+#define _C_UCHR     'C'
+#define _C_SHT      's'
+#define _C_USHT     'S'
+#define _C_INT      'i'
+#define _C_UINT     'I'
+#define _C_LNG      'l'
+#define _C_ULNG     'L'
+#define _C_LNG_LNG  'q'
+#define _C_ULNG_LNG 'Q'
+
+#define _C_FLT      'f'
+#define _C_DBL      'd'
+
+#define _C_BFLD     'b'
+#define _C_VOID     'v'
+#define _C_UNDEF    '?'
+#define _C_PTR      '^'
+
+#define _C_CHARPTR  '*'
+#define _C_ATOM     '%'
+
+#define _C_ARY_B    '['
+#define _C_ARY_E    ']'
+#define _C_UNION_B  '('
+#define _C_UNION_E  ')'
+#define _C_STRUCT_B '{'
+#define _C_STRUCT_E '}'
+#define _C_VECTOR   '!'
+
+#define _C_COMPLEX  'j'
+#define _C_CONST    'r'
+#define _C_IN       'n'
+#define _C_INOUT    'N'
+#define _C_OUT      'o'
+#define _C_BYCOPY   'O'
+#define _C_ONEWAY   'V'
+
+#include "runtime-deprecated.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __LIBOBJC_RUNTIME_H_INCLUDED__
diff --git a/third_party/libobjc/objc/slot.h b/third_party/libobjc/objc/slot.h
new file mode 100644
index 0000000000000000000000000000000000000000..0afd7548adc464879e86acaf3705daf7b748efee
--- /dev/null
+++ b/third_party/libobjc/objc/slot.h
@@ -0,0 +1,44 @@
+#ifndef __OBJC_SLOT_H_INCLUDED__
+#define __OBJC_SLOT_H_INCLUDED__
+/**
+ * The objc_slot structure is used to permit safe IMP caching.  It is returned
+ * by the new lookup APIs.  When you cache an IMP, you should store a copy of
+ * the version field and a pointer to the slot. 
+ *
+ * The slot version is guaranteed never to be 0.  When updating a cache, you
+ * should use code of the following form:
+ *
+ * 1) version = 0;
+ * 2) slot->cachedFor = receiver->isa;
+ * 3) slot_cache = slot;
+ * 4) version = slot->version;
+ *
+ * The runtime guarantees that the version in any cachable slot will never be
+ * 0.  This should ensure that, if the version and cache pointer mismatch, the
+ * next access will cause a cache miss.  
+ *
+ * When using a cached slot, you should compare the owner pointer to the isa
+ * pointer of the receiver and the message and the version of the slot to your
+ * cached version.
+ */
+struct objc_slot
+{
+	/** The class to which this slot is attached (used internally).  */
+	Class owner;
+	/** The class for which this slot was cached.  Note that this can be
+	 * modified by different cache owners, in different threads.  Doing so may
+	 * cause some cache misses, but if different methods are sending messages
+	 * to the same object and sharing a cached slot then it may also improve
+	 * cache hits.  Profiling is probably required here. */
+	Class cachedFor;
+	/** The (typed) selector for the method identified by this slot. */
+	const char *types;
+	/** The current version.  This changes if the method changes or if a
+	 * subclass overrides this method, potentially invalidating this cache. */
+	int version;
+	/** The method pointer for this method. */
+	IMP method;
+	/** Selector for this method. */
+	SEL selector;
+} OBJC_NONPORTABLE;
+#endif // __OBJC_SLOT_H_INCLUDED__
diff --git a/third_party/libobjc/objc/toydispatch.h b/third_party/libobjc/objc/toydispatch.h
new file mode 100644
index 0000000000000000000000000000000000000000..373771477df9e18356909fd8e438ecec1d96c0b2
--- /dev/null
+++ b/third_party/libobjc/objc/toydispatch.h
@@ -0,0 +1,47 @@
+/**
+ * toydispatch implements a (tiny) subset of the libdispatch interfaces.  It
+ * can produce FIFO work queues, but not concurrent ones (although queues are
+ * concurrent with respect to each other, as with libdispatch).  Unlike
+ * libdispatch, queues all run on the same system thread.  This is less
+ * efficient, so the real libdispatch should be used on platforms where it is
+ * available.
+ *
+ * Toydispatch symbol names are prefixed with toy_ so programs can be linked to
+ * both libdispatch and toydispatch.  
+ */
+
+/* If the real libdispatch exists, use that instead of the toy one. */
+#if !defined(__has_include)
+#define __has_include(x) 0
+#endif
+#if __has_include(<dispatch/dispatch.h>) && !defined(__TOY_DISPATCH__)
+#	include <dispatch/dispatch.h>
+#else
+
+/**
+ * Function type for functions that can be added to dispatch queues.
+ */
+typedef void (*dispatch_function_t)(void *);
+
+typedef struct dispatch_queue * dispatch_queue_t;
+
+#define dispatch_queue_create toy_dispatch_queue_create
+/**
+ * Create a new queue.  Both parameters are ignored by toydispatch.
+ */
+dispatch_queue_t dispatch_queue_create(const char *label, void *attr);
+
+#define dispatch_async_f toy_dispatch_async_f
+/**
+ * Add a function to the queue.  
+ */
+void dispatch_async_f(dispatch_queue_t queue,
+                      void *context,
+                      dispatch_function_t work);
+
+#define dispatch_release toy_dispatch_release
+void dispatch_release(dispatch_queue_t queue);
+
+#define dispatch_retain toy_dispatch_retain
+void dispatch_retain(dispatch_queue_t queue);
+#endif
diff --git a/third_party/libobjc/objc_msgSend.S b/third_party/libobjc/objc_msgSend.S
new file mode 100644
index 0000000000000000000000000000000000000000..10e52f344c8559a5a05d58259661a5428d345c5c
--- /dev/null
+++ b/third_party/libobjc/objc_msgSend.S
@@ -0,0 +1,9 @@
+#if __x86_64
+#include "objc_msgSend.x86-64.S"
+#elif __i386
+#include "objc_msgSend.x86-32.S"
+#elif __arm__
+#include "objc_msgSend.arm.S"
+#else
+#warning objc_msgSend() not implemented for your architecture
+#endif
diff --git a/third_party/libobjc/objc_msgSend.arm.S b/third_party/libobjc/objc_msgSend.arm.S
new file mode 100644
index 0000000000000000000000000000000000000000..4934996743070ef0d3744c04cbc25e2c99e9abb4
--- /dev/null
+++ b/third_party/libobjc/objc_msgSend.arm.S
@@ -0,0 +1,113 @@
+#define DTABLE_OFFSET  32
+#define SMALLOBJ_MASK  1
+#define SHIFT_OFFSET   4
+#define DATA_OFFSET    12
+#define SLOT_OFFSET    16
+.syntax unified
+.fpu neon
+
+// Macro for testing: logs a register value to standard error
+.macro LOG reg
+	push {r0-r3, ip,lr}
+	mov r0, \reg
+	bl  logInt(PLT)
+	pop {r0-r3, ip,lr}
+.endm
+
+.macro MSGSEND receiver, sel
+	.fnstart
+	teq    \receiver, 0
+	beq    4f                              // Skip everything if the receiver is nil
+	push   {r4-r6}                         // We're going to use these three as
+	.save  {r4-r6}
+	                                       // scratch registers, so save them now.
+	                                       // These are callee-save, so the unwind library
+	                                       // must be able to restore them, so we need CFI
+	                                       // directives for them, but not for any other pushes
+	tst    \receiver, SMALLOBJ_MASK        // Sets Z if this is not a small int
+
+
+	ldrne  r4, LSmallIntClass              // Small Int class -> r4 if this is a small int
+	ldrne  r4, [r4]
+
+	ldreq  r4, [\receiver]                 // Load class to r4 if not a small int
+
+	ldr    r4, [r4, #DTABLE_OFFSET]        // Dtable -> r4
+
+	ldr    r5, LUninstalledDtable          // &uninstalled_dtable -> r5
+	ldr    r5, [r5]
+
+	teq    r4, r5                          // If dtable == &uninstalled_dtable
+	beq    5f                              // Do a slow lookup
+
+	ldr    r5, [\sel]                      // selector->index -> r5
+
+	ldr    r6, [r4, #SHIFT_OFFSET]        // dtable->shift -> r6
+	ldr    r4, [r4, #DATA_OFFSET]         // dtable->data -> r4
+	
+	teq    r6, #8                         // If this is a small dtable, jump to the small dtable handlers
+	beq    1f
+	teq    r6, #0
+	beq    2f
+
+	and    r6, r5, #0xff0000
+	ldr    r4, [r4, r6, asr#14]
+	ldr    r4, [r4, #DTABLE_OFFSET]        
+1:                                        // dtable16
+	and    r6, r5, #0xff00
+	ldr    r4, [r4, r6, asr#6]
+	ldr    r4, [r4, #DTABLE_OFFSET]        
+2:                                        // dtable8
+	and    r6, r5, #0xff
+	ldr    ip, [r4, r6, asl#2]
+
+	teq    ip, #0                         // If the slot is nil
+	beq    5f                             // Go to the slow path and do the forwarding stuff
+
+	ldr   ip, [ip, #SLOT_OFFSET]          // Load the method from the slot
+
+3: 
+	pop    {r4-r6}                        // Restore the saved callee-save registers
+	mov    pc, ip
+
+4:                                        // Nil receiver
+	mov    r0, 0
+	mov    r1, 0
+	mov    pc, lr
+5:                                        // Slow lookup
+	push   {r0-r4, lr}                    // Save anything that will be clobbered by the call
+	.save  {r0-r4, lr}
+
+
+	push   {\receiver}                    // &self, _cmd in arguments
+	.save  {\receiver}
+	mov    r1, \sel
+
+	bl     slowMsgLookup(PLT)             // This is the only place where the CFI directives have to be accurate...
+	mov    ip, r0                         // IMP -> ip
+
+	pop    {r5}                           // restore (modified) self to r5
+	pop    {r0-r4, lr}                    // Load clobbered registers
+	mov    \receiver, r5
+	b      3b
+	.fnend
+.endm
+
+.globl objc_msgSend_fpret
+	.type	objc_msgSend_fpret, %function
+.globl objc_msgSend
+	.type	objc_msgSend, %function
+objc_msgSend:
+objc_msgSend_fpret:
+	MSGSEND r0, r1
+.globl objc_msgSend_stret
+	.type	objc_msgSend_stret, %function
+objc_msgSend_stret:
+	MSGSEND r1, r2
+
+LSmallIntClass:
+	.long   SmallObjectClasses
+	.align  2
+LUninstalledDtable:
+	.long   uninstalled_dtable
+	.align  2
diff --git a/third_party/libobjc/objc_msgSend.x86-32.S b/third_party/libobjc/objc_msgSend.x86-32.S
new file mode 100644
index 0000000000000000000000000000000000000000..f55f8c3c44f03a7ce5e23ef8b8d11180a2ceb125
--- /dev/null
+++ b/third_party/libobjc/objc_msgSend.x86-32.S
@@ -0,0 +1,100 @@
+#define DTABLE_OFFSET  32
+#define SMALLOBJ_MASK  1
+#define SHIFT_OFFSET   4
+#define DATA_OFFSET    12
+#define SLOT_OFFSET    16
+.macro MSGSEND receiver, sel, fpret
+	.cfi_startproc                        
+	movl  \receiver(%esp), %eax
+	test  %eax, %eax                      # If the receiver is nil
+	jz    4f                              # return nil
+	test  $SMALLOBJ_MASK, %eax            # Check if the receiver is a small object
+	jnz   6f                              # Get the small object class
+
+	mov   (%eax), %eax                    # Load the class
+1:                                        # classLoaded
+	movl  \sel(%esp), %ecx
+	mov   DTABLE_OFFSET(%eax), %eax       # Load the dtable from the class
+	cmpl  uninstalled_dtable, %eax        # If this is not (yet) a valid dtable
+	je    5f                              # Do a slow lookup
+	
+	mov   (%ecx), %ecx                    # Load the selector index
+
+	                                      # Register use at this point:
+	                                      # %eax: dtable
+	                                      # %ecx: Selector index
+	                                      # %edx: selector index fragment
+
+	mov   SHIFT_OFFSET(%eax), %edx        # Load the shift (dtable size)
+	mov   DATA_OFFSET(%eax), %eax         # load the address of the start of the array
+	cmpl  $8, %edx                        # If this is a small dtable, jump to the small dtable handlers
+	je    2f 
+	cmpl  $0, %edx 
+	je    3f 
+
+	mov   %ecx, %edx
+	and   $0xff0000, %edx
+	shrl  $14, %edx                       # Right shift 16, but then left shift by 2 (* sizeof(void*))
+	add   %edx, %eax
+	mov   (%eax), %eax
+	mov   DATA_OFFSET(%eax), %eax
+2:                                        # dtable16:
+	mov   %ecx, %edx
+	and   $0xff00, %edx
+	shrl  $6, %edx
+	add   %edx, %eax
+	mov   (%eax), %eax
+	mov   DATA_OFFSET(%eax), %eax
+3:                                        # dtable8:
+	and   $0xff, %ecx
+	shll  $2, %ecx
+	add   %ecx, %eax
+	mov   (%eax), %eax
+
+	test  %eax, %eax
+	jz    5f                             # Nil slot - invoke some kind of forwarding mechanism
+	mov   SLOT_OFFSET(%eax), %eax
+	jmp   *%eax
+4:                                       # returnNil:
+.if \fpret
+	fldz
+.else 
+	xor   %eax, %eax                     # return 0 (int)
+	xor   %edx, %edx                     # Return 64-bit zero (%edx is
+	                                     # caller-save, so it's safe to do this in the general case.
+.endif
+	ret
+5:                                       # slowSend:
+	mov   \sel(%esp), %ecx
+	lea   \receiver(%esp), %eax
+
+	push  %ecx                           # _cmd
+	push  %eax                           # &self
+	.cfi_def_cfa_offset 12
+	call  slowMsgLookup@PLT
+	add   $8, %esp                       # restore the stack
+
+
+	jmp   *%eax
+6:                                        # smallObject:
+	push  %ebx                           # Save old %ebx
+	call  __i686.get_pc_thunk.bx
+	addl  $_GLOBAL_OFFSET_TABLE_, %ebx
+	mov   SmallObjectClasses@GOT(%ebx), %eax
+	mov   (%eax), %eax
+	popl  %ebx
+	jmp   1b 
+	.cfi_endproc
+.endm
+.globl objc_msgSend_fpret
+	.type	objc_msgSend_fpret, @function
+objc_msgSend_fpret:
+	MSGSEND 4, 8, 1
+.globl objc_msgSend
+	.type	objc_msgSend, @function
+objc_msgSend:
+	MSGSEND 4, 8, 0
+.globl objc_msgSend_stret
+	.type	objc_msgSend_stret, @function
+objc_msgSend_stret:
+	MSGSEND 8, 12, 0
diff --git a/third_party/libobjc/objc_msgSend.x86-64.S b/third_party/libobjc/objc_msgSend.x86-64.S
new file mode 100644
index 0000000000000000000000000000000000000000..8ce012baf0dc47455cadde3d0808c58012334522
--- /dev/null
+++ b/third_party/libobjc/objc_msgSend.x86-64.S
@@ -0,0 +1,144 @@
+#define DTABLE_OFFSET  64
+#define SMALLOBJ_MASK  7
+#define SHIFT_OFFSET   4
+#define DATA_OFFSET    16
+#define SLOT_OFFSET    32
+
+.macro MSGSEND receiver, sel
+	.cfi_startproc                        # Start emitting unwind data.  We
+	                                      # don't actually care about any of
+	                                      # the stuff except the slow call,
+	                                      # because that's the only one that
+	                                      # can throw.
+
+	test  \receiver, \receiver            # If the receiver is nil
+	jz    4f                              # return nil
+	movq  $SMALLOBJ_MASK, %r10            # Load the small object mask
+	test  \receiver, %r10                 # Check if the receiver is a small object
+	jnz   6f                              # Get the small object class
+
+	mov   (\receiver), %r10               # Load the dtable from the class
+1:                                        # classLoaded
+	mov   DTABLE_OFFSET(%r10), %r10       # Load the dtable from the class
+	cmpq  uninstalled_dtable(%rip), %r10  # If this is not (yet) a valid dtable
+	je    5f                              # Do a slow lookup
+	
+	push  %r12
+	push  %r13
+
+	mov   (\sel), %r11                    # Load the selector index
+	mov   SHIFT_OFFSET(%r10), %r13        # Load the shift (dtable size)
+	mov   DATA_OFFSET(%r10), %r12         # load the address of the start of the array
+	cmpl  $8, %r13d                       # If this is a small dtable, jump to the small dtable handlers
+	je    2f 
+	cmpl  $0, %r13d
+	je    3f 
+
+	mov   %r11, %r13
+	and   $0xff0000, %r13
+	shrl  $13, %r13d                      # Right shift 16, but then left shift by 3 *sizeof(void*)
+	add   %r13, %r12
+	mov   (%r12), %r12
+	mov   DATA_OFFSET(%r12), %r12
+2:                                        # dtable16:
+	mov   %r11, %r13
+	and   $0xff00, %r13
+	shrl  $5, %r13d
+	add   %r13, %r12
+	mov   (%r12), %r12
+	mov   DATA_OFFSET(%r12), %r12
+3:                                       # dtable8:
+	mov   %r11, %r13
+	and   $0xff, %r13
+	shll  $3, %r13d
+	add   %r13, %r12
+	mov   (%r12), %r10
+	pop   %r13
+	pop   %r12
+	test  %r10, %r10
+	jz    5f                             # Nil slot - invoke some kind of forwarding mechanism
+	mov   SLOT_OFFSET(%r10), %r10
+	jmp   *%r10
+4:                                       # returnNil:
+	                                     # Both of the return registers are
+	                                     # callee-save on x86-64, so we can
+	                                     # return 0 in both in the same code:
+	xor   %rax, %rax                     # Return 0 as an integer
+	pxor  %xmm0, %xmm0                   # Return 0 as a floating point value
+	ret
+5:                                       # slowSend:
+	push  %rax                           # We need to preserve all registers that may contain arguments:
+	push  %rbx
+	push  %rcx
+	push  %r8
+	push  %r9
+	
+	sub $0x98, %rsp
+	movups	%xmm0, 0x80(%rsp)
+	movups	%xmm1, 0x70(%rsp)
+	movups	%xmm2, 0x60(%rsp)
+	movups	%xmm3, 0x50(%rsp)
+	movups	%xmm4, 0x40(%rsp)
+	movups	%xmm5, 0x30(%rsp)
+	movups	%xmm6, 0x20(%rsp)
+	movups	%xmm7, 0x10(%rsp)
+
+#rdi rsi rdx
+	# We're (potentially) modifying the self argument with the lookup, so we don't want to be 
+.ifc "\receiver", "%rdi"
+	push  %rdi
+	mov   %rsp, %rdi
+	push  %rsi                           # Save _cmd (not preserved across calls)
+	push  %rdx
+.else
+	push  %rdi                           # Save the sret pointer
+	push  %rsi                           # Save self where it can be modified
+	mov   %rsp, %rdi
+	push  %rdx
+	mov   %rdx, %rsi                     # move _cmd to where the callee expects it to be
+.endif
+
+	.cfi_adjust_cfa_offset 0xD8
+	call  slowMsgLookup                  # Call the slow lookup function
+	mov   %rax, %r10                     # Load the returned IMP
+
+	pop   %rdx
+	pop   %rsi
+	pop   %rdi
+
+	movups	0x80(%rsp), %xmm0
+	movups	0x70(%rsp), %xmm1
+	movups	0x60(%rsp), %xmm2
+	movups	0x50(%rsp), %xmm3
+	movups	0x40(%rsp), %xmm4
+	movups	0x30(%rsp), %xmm5
+	movups	0x20(%rsp), %xmm6
+	movups	0x10(%rsp), %xmm7
+	add   $0x98, %rsp
+
+	pop   %r9
+	pop   %r8
+	pop   %rcx
+	pop   %rbx
+	pop   %rax
+	jmp   *%r10
+6:                                        # smallObject:
+	and   \receiver, %r10                 # Find the small int type
+	shll  $3, %r10d
+	lea   SmallObjectClasses(%rip), %r11
+	add   %r11, %r10
+	mov   (%r10), %r10
+	jmp   1b 
+	.cfi_endproc
+.endm
+.globl objc_msgSend
+	.type	objc_msgSend, @function
+.globl objc_msgSend_fpret
+	.type	objc_msgSend_fpret, @function
+objc_msgSend_fpret:
+objc_msgSend:
+	MSGSEND %rdi, %rsi
+.globl objc_msgSend_stret
+	.type	objc_msgSend_stret, @function
+objc_msgSend_stret:
+	MSGSEND %rsi, %rdx
diff --git a/third_party/libobjc/objcxx_eh.cc b/third_party/libobjc/objcxx_eh.cc
new file mode 100644
index 0000000000000000000000000000000000000000..0a29c3ce7378082d5942e557eb60e95501783454
--- /dev/null
+++ b/third_party/libobjc/objcxx_eh.cc
@@ -0,0 +1,241 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include "dwarf_eh.h"
+#include "objcxx_eh.h"
+#include <exception>
+
+extern "C" 
+{
+#include "objc/runtime.h"
+};
+namespace __cxxabiv1
+{
+	struct __class_type_info;
+}
+
+using __cxxabiv1::__class_type_info;
+
+namespace std
+{
+	/**
+	 * std::type_info defined with the GCC ABI.  This may not be exposed in
+	 * public headers, but is required for correctly implementing the unified
+	 * exception model.
+	 */
+	class type_info
+	{
+				public:
+				virtual ~type_info();
+				bool operator==(const type_info &) const;
+				bool operator!=(const type_info &) const;
+				bool before(const type_info &) const;
+				const char* name() const;
+				type_info();
+				private:
+				type_info(const type_info& rhs);
+				type_info& operator= (const type_info& rhs);
+				const char *__type_name;
+				protected:
+				type_info(const char *name): __type_name(name) { }
+				public:
+				virtual bool __is_pointer_p() const;
+				virtual bool __is_function_p() const;
+				virtual bool __do_catch(const type_info *thrown_type,
+				                        void **thrown_object,
+				                        unsigned outer) const;
+				virtual bool __do_upcast(
+				                const __class_type_info *target,
+				                void **thrown_object) const;
+	};
+}
+
+using namespace std;
+
+
+static BOOL isKindOfClass(Class thrown, Class type)
+{
+	do
+	{
+		if (thrown == type)
+		{
+			return YES;
+		}
+		thrown = class_getSuperclass(thrown);
+	} while (Nil != thrown);
+
+	return NO;
+}
+
+/**
+ * C++ Exception structure.  From the Itanium ABI spec
+ */
+struct __cxa_exception
+{
+	std::type_info *exceptionType;
+	void (*exceptionDestructor) (void *);
+	unexpected_handler unexpectedHandler;
+	terminate_handler terminateHandler;
+	__cxa_exception *nextException;
+	unsigned int handlerCount;
+	int handlerSwitchValue;
+	const char *actionRecord;
+	const char *languageSpecificData;
+	void *catchTemp;
+	void *adjustedPtr;
+	_Unwind_Exception unwindHeader;
+};
+
+
+
+
+namespace gnustep
+{
+	namespace libobjc
+	{
+		struct __objc_id_type_info : std::type_info
+		{
+			__objc_id_type_info() : type_info("@id") {};
+			virtual ~__objc_id_type_info();
+			virtual bool __do_catch(const type_info *thrownType,
+			                        void **obj,
+			                        unsigned outer) const;
+		};
+		struct __objc_class_type_info : std::type_info
+		{
+			virtual ~__objc_class_type_info();
+			virtual bool __do_catch(const type_info *thrownType,
+			                        void **obj,
+			                        unsigned outer) const;
+		};
+	}
+};
+
+
+static bool AppleCompatibleMode = true;
+extern "C" int objc_set_apple_compatible_objcxx_exceptions(int newValue)
+{
+	bool old = AppleCompatibleMode;
+	AppleCompatibleMode = newValue;
+	return old;
+}
+
+gnustep::libobjc::__objc_class_type_info::~__objc_class_type_info() {}
+gnustep::libobjc::__objc_id_type_info::~__objc_id_type_info() {}
+bool gnustep::libobjc::__objc_class_type_info::__do_catch(const type_info *thrownType,
+                                                          void **obj,
+                                                          unsigned outer) const
+{
+	id thrown = (id)obj;
+	bool found = false;
+	// Id throw matches any ObjC catch.  This may be a silly idea!
+	if (dynamic_cast<const __objc_id_type_info*>(thrownType)
+	    || (AppleCompatibleMode && 
+	        dynamic_cast<const __objc_class_type_info*>(thrownType)))
+	{
+		thrown = **(id**)obj;
+		// nil only matches id catch handlers in Apple-compatible mode, or when thrown as an id
+		if (0 == thrown)
+		{
+			return false;
+		}
+		// Check whether the real thrown object matches the catch type.
+		found = isKindOfClass(object_getClass(thrown),
+		                      (Class)objc_getClass(name()));
+	}
+	else if (dynamic_cast<const __objc_class_type_info*>(thrownType))
+	{
+		thrown = **(id**)obj;
+		found = isKindOfClass((Class)objc_getClass(thrownType->name()),
+		                      (Class)objc_getClass(name()));
+	}
+	if (found)
+	{
+		*obj = (void*)thrown;
+	}
+	return found;
+};
+
+bool gnustep::libobjc::__objc_id_type_info::__do_catch(const type_info *thrownType,
+                                                       void **obj,
+                                                       unsigned outer) const
+{
+	// Id catch matches any ObjC throw
+	if (dynamic_cast<const __objc_class_type_info*>(thrownType))
+	{
+		*obj = **(id**)obj;
+		return true;
+	}
+	if (dynamic_cast<const __objc_id_type_info*>(thrownType))
+	{
+		*obj = **(id**)obj;
+		return true;
+	}
+	return false;
+};
+
+/**
+ * Public interface to the Objective-C++ exception mechanism
+ */
+extern "C"
+{
+/**
+ * The public symbol that the compiler uses to indicate the Objective-C id type.
+ */
+gnustep::libobjc::__objc_id_type_info __objc_id_type_info;
+
+/**
+ * Exception cleanup function for C++ exceptions that wrap Objective-C
+ * exceptions.
+ */
+static void exception_cleanup(_Unwind_Reason_Code reason,
+                              struct _Unwind_Exception *ex)
+{
+	__cxa_exception *cxxex = (__cxa_exception*) ((char*)ex - offsetof(struct __cxa_exception, unwindHeader));
+	if (cxxex->exceptionType != &__objc_id_type_info)
+	{
+		delete cxxex->exceptionType;
+	}
+	__cxa_free_exception((void*)ex);
+}
+
+struct _Unwind_Exception *objc_init_cxx_exception(void *thrown_exception)
+{
+	__cxa_exception *ex = ((__cxa_exception*)thrown_exception) - 1;
+
+	std::type_info *tinfo = &__objc_id_type_info;
+
+	ex->exceptionType = tinfo;
+
+	ex->exceptionDestructor = 0;
+
+	ex->unwindHeader.exception_class = EXCEPTION_CLASS('G','N','U','C','C','+','+','\0');
+	ex->unwindHeader.exception_cleanup = exception_cleanup;
+
+	return &ex->unwindHeader;
+}
+
+void* objc_object_for_cxx_exception(void *thrown_exception)
+{
+	__cxa_exception *ex = (__cxa_exception*) ((char*)thrown_exception -
+			offsetof(struct __cxa_exception, unwindHeader));
+	const std::type_info *thrownType = ex->exceptionType;
+	if (!dynamic_cast<const gnustep::libobjc::__objc_id_type_info*>(thrownType) && 
+	    !dynamic_cast<const gnustep::libobjc::__objc_class_type_info*>(thrownType))
+	{
+		return (id)-1;
+	}
+	return *(id*)(ex+1);
+}
+
+/*
+void print_type_info(void *thrown_exception)
+{
+	__cxa_exception *ex = (__cxa_exception*) ((char*)thrown_exception -
+			offsetof(struct __cxa_exception, unwindHeader));
+	fprintf(stderr, "Type info: %s\n", ex->exceptionType->name());
+	fprintf(stderr, "offset is: %d\n", offsetof(struct __cxa_exception, unwindHeader));
+}
+*/
+
+} // extern "C"
+
diff --git a/third_party/libobjc/objcxx_eh.h b/third_party/libobjc/objcxx_eh.h
new file mode 100644
index 0000000000000000000000000000000000000000..9866105504cb77f57d009a9eb06abb853ee827ea
--- /dev/null
+++ b/third_party/libobjc/objcxx_eh.h
@@ -0,0 +1,47 @@
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**
+ * Allocates a C++ exception.  This function is part of the Itanium C++ ABI and
+ * is provided externally.
+ */
+__attribute__((weak))
+void *__cxa_allocate_exception(size_t thrown_size);
+/**
+ * Initialises an exception object returned by __cxa_allocate_exception() for
+ * storing an Objective-C object.  The return value is the location of the
+ * _Unwind_Exception structure within this structure, and should be passed to
+ * the C++ personality function.
+ */
+__attribute__((weak))
+struct _Unwind_Exception *objc_init_cxx_exception(void *thrown_exception);
+/**
+ * The GNU C++ exception personality function, provided by libsupc++ (GNU) or
+ * libcxxrt (PathScale).
+ */
+__attribute__((weak)) DECLARE_PERSONALITY_FUNCTION(__gxx_personality_v0);
+/**
+ * Frees an exception object allocated by __cxa_allocate_exception().  Part of
+ * the Itanium C++ ABI.
+ */
+__attribute__((weak))
+void __cxa_free_exception(void *thrown_exception);
+/**
+ * Tests whether a C++ exception contains an Objective-C object, and returns if
+ * if it does.  Returns -1 if it doesn't.  -1 is used instead of 0, because
+ * throwing nil is allowed, but throwing non-nil, invalid objects is not.
+ */
+__attribute__((weak))
+void *objc_object_for_cxx_exception(void *thrown_exception);
+
+/**
+ * Prints the type info associated with an exception.  Used only when
+ * debugging, not compiled in the normal build.
+ */
+__attribute__((weak))
+void print_type_info(void *thrown_exception);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/third_party/libobjc/opts/CMakeLists.txt b/third_party/libobjc/opts/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e017de8fb0b45e9c0f2d12da0564541a7e1ed401
--- /dev/null
+++ b/third_party/libobjc/opts/CMakeLists.txt
@@ -0,0 +1,22 @@
+add_llvm_loadable_module( libGNUObjCRuntime
+  ClassIMPCache.cpp
+  ClassMethodInliner.cpp
+  IvarPass.cpp
+  ObjectiveCOpts.cpp
+  TypeFeedbackDrivenInliner.cpp
+  ClassLookupCache.cpp
+  IMPCacher.cpp
+  LoopIMPCachePass.cpp
+  TypeFeedback.cpp
+)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-variadic-macros -DLLVM_MAJOR=3 -DLLVM_MINOR=0")
+
+add_llvm_library_dependencies( libGNUObjCRuntime
+  LLVMAnalysis
+  LLVMCore
+  LLVMSupport
+  LLVMTarget
+  LLVMipa
+  LLVMipo
+)
diff --git a/third_party/libobjc/opts/COPYING b/third_party/libobjc/opts/COPYING
new file mode 100644
index 0000000000000000000000000000000000000000..8647a56b739dfc73c8501a1a06ecbd7e75f737e4
--- /dev/null
+++ b/third_party/libobjc/opts/COPYING
@@ -0,0 +1,20 @@
+Copyright (c) 2009 David Chisnall
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
diff --git a/third_party/libobjc/opts/ClassIMPCache.cpp b/third_party/libobjc/opts/ClassIMPCache.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e427eeca6cec0c8e52c634f3c553142153a722dc
--- /dev/null
+++ b/third_party/libobjc/opts/ClassIMPCache.cpp
@@ -0,0 +1,112 @@
+#include "llvm/Pass.h"
+#include "llvm/Function.h"
+#include "llvm/Module.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/Instructions.h"
+#include "llvm/Constants.h"
+#include "llvm/GlobalVariable.h"
+#include "llvm/Support/CallSite.h"
+#include "llvm/Support/IRBuilder.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/DefaultPasses.h"
+#include "ObjectiveCOpts.h"
+#include "IMPCacher.h"
+#include <string>
+#include "LLVMCompat.h"
+
+using namespace GNUstep;
+using namespace llvm;
+using std::string;
+
+namespace 
+{
+  class ClassIMPCachePass : public ModulePass 
+  {
+    LLVMIntegerType *IntTy;
+
+    public:
+    static char ID;
+    ClassIMPCachePass() : ModulePass(ID) {}
+
+    virtual bool runOnModule(Module &M) {
+      Function *sendFn = M.getFunction("objc_msgSend");
+      Function *send_stretFn = M.getFunction("objc_msgSend_stret");
+      Function *send_fpretFn = M.getFunction("objc_msgSend_fpret");
+      Function *lookupFn =M.getFunction("objc_msg_lookup_sender");
+      // If this module doesn't contain any message sends, then skip it
+      if ((sendFn == 0) && (send_stretFn == 0) && (send_fpretFn == 0) &&
+          (lookupFn ==0)) { return false; }
+
+      GNUstep::IMPCacher cacher = GNUstep::IMPCacher(M.getContext(), this);
+      IntTy = (sizeof(int) == 4 ) ? Type::getInt32Ty(M.getContext()) :
+          Type::getInt64Ty(M.getContext()) ;
+      bool modified = false;
+
+      unsigned MessageSendMDKind = M.getContext().getMDKindID("GNUObjCMessageSend");
+
+      for (Module::iterator F=M.begin(), fend=M.end() ;
+          F != fend ; ++F) {
+
+        if (F->isDeclaration()) { continue; }
+
+        SmallVector<std::pair<CallSite, bool>, 16> Lookups;
+        SmallVector<CallSite, 16> Sends;
+
+        for (Function::iterator i=F->begin(), end=F->end() ;
+            i != end ; ++i) {
+          for (BasicBlock::iterator b=i->begin(), last=i->end() ;
+              b != last ; ++b) {
+            CallSite call(b);
+            if (call.getInstruction()) {
+              Value *callee = call.getCalledValue()->stripPointerCasts();
+              if (Function *func = dyn_cast<Function>(callee)) {
+                if ((func == lookupFn) || (func == sendFn) ||
+                    (func == send_fpretFn) || (func == send_stretFn)) {
+                  MDNode *messageType = 
+                    call.getInstruction()->getMetadata(MessageSendMDKind);
+                  if (0 == messageType) { continue; }
+                  if (cast<ConstantInt>(messageType->getOperand(2))->isOne()) {
+                    if (func == lookupFn) {
+                      Lookups.push_back(std::pair<CallSite, bool>(call, false));
+                    } else {
+                      Sends.push_back(call);
+                    }
+                  }
+                } else if (func->getName() == "objc_slot_lookup_super") {
+                  Lookups.push_back(std::pair<CallSite, bool>(call, true));
+                }
+              }
+            }
+          }
+        }
+        for (SmallVectorImpl<CallSite>::iterator i=Sends.begin(), 
+            e=Sends.end() ; e!=i ; i++) {
+          Lookups.push_back(std::pair<CallSite, bool>(cacher.SplitSend(*i), false));
+        }
+        for (SmallVectorImpl<std::pair<CallSite, bool> >::iterator
+            i=Lookups.begin(), e=Lookups.end() ; e!=i ; i++) {
+          Instruction *call = i->first.getInstruction();
+          LLVMType *SlotPtrTy = call->getType();
+
+          Value *slot = new GlobalVariable(M, SlotPtrTy, false,
+              GlobalValue::PrivateLinkage, Constant::getNullValue(SlotPtrTy),
+              "slot");
+          Value *version = new GlobalVariable(M, IntTy, false,
+              GlobalValue::PrivateLinkage, Constant::getNullValue(IntTy),
+              "version");
+          cacher.CacheLookup(call, slot, version, i->second);
+        }
+      }
+      return modified;
+    }
+  };
+
+  char ClassIMPCachePass::ID = 0;
+  RegisterPass<ClassIMPCachePass> X("gnu-class-imp-cache", 
+          "Cache IMPs for class messages");
+}
+
+ModulePass *createClassIMPCachePass(void)
+{
+  return new ClassIMPCachePass();
+}
diff --git a/third_party/libobjc/opts/ClassLookupCache.cpp b/third_party/libobjc/opts/ClassLookupCache.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0f74cf0e4678f779cffb320482aca05b7b2436db
--- /dev/null
+++ b/third_party/libobjc/opts/ClassLookupCache.cpp
@@ -0,0 +1,160 @@
+#include "llvm/Pass.h"
+#include "llvm/Function.h"
+#include "llvm/Module.h"
+#include "llvm/Instructions.h"
+#include "llvm/Constants.h"
+#include "llvm/GlobalVariable.h"
+#include "llvm/Support/IRBuilder.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/DefaultPasses.h"
+#include "ObjectiveCOpts.h"
+#include <string>
+
+#include "IMPCacher.h"
+#include "LLVMCompat.h"
+
+using namespace llvm;
+using namespace GNUstep;
+using std::string;
+using std::pair;
+
+namespace 
+{
+  class ClassLookupCachePass : public ModulePass {
+    /// Module that we're currently optimising
+    Module *M;
+    /// Static cache.  If we're not using the non-fragile ABI, then we cache
+    /// all class lookups in static variables to avoid the overhead of the
+    /// lookup.  With the non-fragile ABI, we don't need to do this.
+    llvm::StringMap<GlobalVariable*> statics;
+
+    typedef std::pair<CallInst*,std::string> ClassLookup;
+
+    public:
+    static char ID;
+    ClassLookupCachePass() : ModulePass(ID) {}
+
+    virtual bool doInitialization(Module &Mod) {
+      M = &Mod;
+      return false;  
+    }
+
+    bool runOnFunction(Function &F) {
+      bool modified = false;
+      SmallVector<ClassLookup, 16> Lookups;
+
+      for (Function::iterator i=F.begin(), end=F.end() ;
+          i != end ; ++i) {
+        for (BasicBlock::iterator b=i->begin(), last=i->end() ;
+            b != last ; ++b) {
+          if (CallInst *call = dyn_cast<CallInst>(b)) {
+            if (Function *func = call->getCalledFunction()) {
+              if (func->getName() == "objc_lookup_class") {
+                ClassLookup lookup;
+                GlobalVariable *classNameVar = dyn_cast<GlobalVariable>(
+                    call->getOperand(0)->stripPointerCasts());
+                if (0 == classNameVar) { continue; }
+#if (LLVM_MAJOR > 3) || ((LLVM_MAJOR == 3) && (LLVM_MINOR > 0))
+                ConstantDataArray *init = dyn_cast<ConstantDataArray>(
+                    classNameVar->getInitializer());
+#else
+                ConstantArray *init = dyn_cast<ConstantArray>(
+                    classNameVar->getInitializer());
+#endif
+                if (0 == init || !init->isCString()) { continue; }
+                lookup.first = call;
+                lookup.second = init->getAsString();
+                modified = true;
+                Lookups.push_back(lookup);
+              }
+            }
+          }
+        }
+      }
+      for (SmallVectorImpl<ClassLookup>::iterator i=Lookups.begin(), 
+          e=Lookups.end() ; e!=i ; i++) {
+        llvm::Instruction *lookup = i->first;
+        std::string &cls = i->second;
+        LLVMType *clsTy = lookup->getType();
+        Value *global = M->getGlobalVariable(("_OBJC_CLASS_" + i->second).c_str(), true);
+        global = 0;
+        // If we can see the class reference for this, then reference it
+        // directly.  If not, then do the lookup and cache it.
+        if (global) {
+          // Insert a bitcast of the class to the required type where the
+          // lookup is and then replace all references to the lookup with it.
+          Value *cls = new BitCastInst(global, clsTy, "class", lookup);
+          lookup->replaceAllUsesWith(cls);
+          lookup->removeFromParent();
+        } else {
+          GlobalVariable *cache = statics[cls];
+          if (!cache) {
+            cache = new GlobalVariable(*M, clsTy, false,
+                GlobalVariable::PrivateLinkage, Constant::getNullValue(clsTy),
+                ".class_cache");
+            statics[cls] = cache;
+          }
+          BasicBlock *beforeLookupBB = lookup->getParent();
+          BasicBlock *lookupBB = SplitBlock(beforeLookupBB, lookup, this);
+          BasicBlock::iterator iter = lookup;
+          iter++;
+          BasicBlock *afterLookupBB = SplitBlock(iter->getParent(), iter, this);
+          // SplitBlock() adds an unconditional branch, which we don't want.
+          // Remove it.
+          removeTerminator(beforeLookupBB);
+          removeTerminator(lookupBB);
+
+          PHINode *phi = CreatePHI(clsTy, 2, cls, afterLookupBB->begin());
+          // We replace all of the existing uses with the PHI node now, because
+          // we're going to add some more uses later that we don't want
+          // replaced.
+          lookup->replaceAllUsesWith(phi);
+
+          // In the original basic block, we test whether the cache is NULL,
+          // and skip the lookup if it isn't.
+          IRBuilder<> B(beforeLookupBB);
+          llvm::Value *cachedClass =
+            B.CreateBitCast(B.CreateLoad(cache), clsTy);
+          llvm::Value *needsLookup = B.CreateIsNull(cachedClass);
+          B.CreateCondBr(needsLookup, lookupBB, afterLookupBB);
+          // In the lookup basic block, we just do the lookup, store it in the
+          // cache, and then jump to the continue block
+          B.SetInsertPoint(lookupBB);
+          B.CreateStore(lookup, cache);
+          B.CreateBr(afterLookupBB);
+          // Now we just need to set the PHI node to use the cache or the
+          // lookup result
+          phi->addIncoming(cachedClass, beforeLookupBB);
+          phi->addIncoming(lookup, lookupBB);
+        }
+      }
+      return modified;
+    }
+    virtual bool runOnModule(Module &Mod) {
+      statics.empty();
+      M = &Mod;
+      bool modified = false;
+
+      for (Module::iterator F=Mod.begin(), fend=Mod.end() ;
+          F != fend ; ++F) {
+
+        if (F->isDeclaration()) { continue; }
+
+        modified |= runOnFunction(*F);
+      }
+
+      return modified;
+    };
+  };
+
+  char ClassLookupCachePass::ID = 0;
+  RegisterPass<ClassLookupCachePass> X("gnu-class-lookup-cache", 
+          "Cache class lookups");
+}
+
+ModulePass *createClassLookupCachePass(void)
+{
+  return new ClassLookupCachePass();
+}
diff --git a/third_party/libobjc/opts/ClassMethodInliner.cpp b/third_party/libobjc/opts/ClassMethodInliner.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..dff8b7154a5cdb481f059ce4c26da0b178893a78
--- /dev/null
+++ b/third_party/libobjc/opts/ClassMethodInliner.cpp
@@ -0,0 +1,114 @@
+#include "llvm/Pass.h"
+#include "llvm/Function.h"
+#include "llvm/Module.h"
+#include "llvm/Instructions.h"
+#include "llvm/Support/CallSite.h"
+#include "llvm/Constants.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/GlobalVariable.h"
+#include "llvm/Support/IRBuilder.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/InlineCost.h"
+#include "llvm/DefaultPasses.h"
+#include "ObjectiveCOpts.h"
+#include "IMPCacher.h"
+#include <string>
+
+using namespace llvm;
+using namespace GNUstep;
+using std::string;
+
+// Mangle a method name
+//
+// From clang:
+static std::string SymbolNameForMethod(const std::string &ClassName, const
+      std::string &CategoryName, const std::string &MethodName, bool isClassMethod)
+{
+    std::string MethodNameColonStripped = MethodName;
+      std::replace(MethodNameColonStripped.begin(), MethodNameColonStripped.end(),
+                ':', '_');
+        return std::string(isClassMethod ? "_c_" : "_i_") + ClassName + "_" +
+              CategoryName + "_" + MethodNameColonStripped;
+}
+
+namespace 
+{
+  class ClassMethodInliner : public ModulePass 
+  {
+    const IntegerType *IntTy;
+
+    public:
+    static char ID;
+    ClassMethodInliner() : ModulePass(ID) {}
+
+    virtual bool runOnModule(Module &M) {
+      unsigned MessageSendMDKind = M.getContext().getMDKindID("GNUObjCMessageSend");
+      InlineCostAnalyzer CA;
+      SmallPtrSet<const Function *, 16> NeverInline;
+
+      GNUstep::IMPCacher cacher = GNUstep::IMPCacher(M.getContext(), this);
+      IntTy = (sizeof(int) == 4 ) ? Type::getInt32Ty(M.getContext()) :
+          Type::getInt64Ty(M.getContext()) ;
+      bool modified = false;
+
+      for (Module::iterator F=M.begin(), fend=M.end() ;
+          F != fend ; ++F) {
+
+        SmallVector<CallSite, 16> messages;
+
+        if (F->isDeclaration()) { continue; }
+
+        for (Function::iterator i=F->begin(), end=F->end() ;
+            i != end ; ++i) {
+          for (BasicBlock::iterator b=i->begin(), last=i->end() ;
+              b != last ; ++b) {
+            CallSite call(b);
+            if (call.getInstruction() && !call.getCalledFunction()) {
+              MDNode *messageType = call->getMetadata(MessageSendMDKind);
+              if (0 == messageType) { continue; }
+              messages.push_back(call);
+            }
+          }
+        }
+        for (SmallVectorImpl<CallSite>::iterator i=messages.begin(), 
+            e=messages.end() ; e!=i ; i++) {
+
+          MDNode *messageType = (*i)->getMetadata(MessageSendMDKind);
+          StringRef sel = 
+                cast<MDString>(messageType->getOperand(0))->getString();
+          StringRef cls = 
+                cast<MDString>(messageType->getOperand(1))->getString();
+          bool isClassMethod = 
+                cast<ConstantInt>(messageType->getOperand(2))->isOne();
+          std::string functionName = SymbolNameForMethod(cls, "", sel, isClassMethod);
+          Function *method = M.getFunction(functionName);
+
+          if (0 == method || method->isDeclaration()) { continue; }
+
+#if (LLVM_MAJOR > 3) || ((LLVM_MAJOR == 3) && (LLVM_MINOR > 0))
+          InlineCost IC = CA.getInlineCost((*i), method, 200);
+#else
+          InlineCost IC = CA.getInlineCost((*i), method, NeverInline);
+#define getCost getValue
+#endif
+          // FIXME: 200 is a random number.  Pick a better one!
+          if (IC.isAlways() || (IC.isVariable() && IC.getCost() < 200)) {
+            cacher.SpeculativelyInline((*i).getInstruction(), method);
+            i->getInstruction()->setMetadata(MessageSendMDKind, 0);
+            modified = true;
+          }
+        }
+      }
+      return modified;
+    }
+  };
+
+  char ClassMethodInliner::ID = 0;
+  RegisterPass<ClassMethodInliner> X("gnu-class-method-inline", 
+          "Inline class methods and message sends to super");
+}
+
+ModulePass *createClassMethodInliner(void)
+{
+  return new ClassMethodInliner();
+}
diff --git a/third_party/libobjc/opts/IMPCacher.cpp b/third_party/libobjc/opts/IMPCacher.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b6b5f49e510c6c0f4b02fdc1579140ba3dd87a64
--- /dev/null
+++ b/third_party/libobjc/opts/IMPCacher.cpp
@@ -0,0 +1,303 @@
+#include "llvm/Analysis/Verifier.h"
+#include "IMPCacher.h"
+#include "llvm/Pass.h"
+#include "llvm/Function.h"
+#include "llvm/Module.h"
+#include "llvm/Instructions.h"
+#include "llvm/Constants.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/Metadata.h"
+#include "llvm/Support/IRBuilder.h"
+#include "llvm/Support/CallSite.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+
+#include "LLVMCompat.h"
+
+GNUstep::IMPCacher::IMPCacher(LLVMContext &C, Pass *owner) : Context(C),
+  Owner(owner) {
+
+  PtrTy = Type::getInt8PtrTy(Context);
+  IntTy = (sizeof(int) == 4 ) ? Type::getInt32Ty(C) : Type::getInt64Ty(C);
+  IdTy = PointerType::getUnqual(PtrTy);
+  Value *AlreadyCachedFlagValue = MDString::get(C, "IMPCached");
+  AlreadyCachedFlag = CreateMDNode(C, &AlreadyCachedFlagValue);
+  IMPCacheFlagKind = Context.getMDKindID("IMPCache");
+}
+
+void GNUstep::IMPCacher::CacheLookup(Instruction *lookup, Value *slot, Value
+    *version, bool isSuperMessage) {
+
+  // If this IMP is already cached, don't cache it again.
+  if (lookup->getMetadata(IMPCacheFlagKind)) { return; }
+
+  lookup->setMetadata(IMPCacheFlagKind, AlreadyCachedFlag);
+  bool isInvoke = false;
+
+  BasicBlock *beforeLookupBB = lookup->getParent();
+  BasicBlock *lookupBB = SplitBlock(beforeLookupBB, lookup, Owner);
+  BasicBlock *lookupFinishedBB = lookupBB;
+  BasicBlock *afterLookupBB;
+
+  if (InvokeInst *inv = dyn_cast<InvokeInst>(lookup)) {
+    afterLookupBB = inv->getNormalDest();
+    lookupFinishedBB =
+      BasicBlock::Create(Context, "done_lookup", lookupBB->getParent()); 
+    CGBuilder B(lookupFinishedBB);
+    B.CreateBr(afterLookupBB);
+    inv->setNormalDest(lookupFinishedBB);
+    isInvoke = true;
+  } else {
+    BasicBlock::iterator iter = lookup;
+    iter++;
+    afterLookupBB = SplitBlock(iter->getParent(), iter, Owner);
+  }
+
+  removeTerminator(beforeLookupBB);
+
+  CGBuilder B = CGBuilder(beforeLookupBB);
+  // Load the slot and check that neither it nor the version is 0.
+  Value *versionValue = B.CreateLoad(version);
+  Value *receiverPtr = lookup->getOperand(0);
+  Value *receiver = receiverPtr;
+  if (!isSuperMessage) {
+    receiver = B.CreateLoad(receiverPtr);
+  }
+  // For small objects, we skip the cache entirely.  
+  // FIXME: Class messages are never to small objects...
+  bool is64Bit = llvm::Module::Pointer64 ==
+    B.GetInsertBlock()->getParent()->getParent()->getPointerSize();
+  LLVMType *intPtrTy = is64Bit ? Type::getInt64Ty(Context) :
+    Type::getInt32Ty(Context);
+
+  // Receiver as an integer
+  Value *receiverSmallObject = B.CreatePtrToInt(receiver, intPtrTy);
+  // Receiver is a small object...
+  receiverSmallObject =
+    B.CreateAnd(receiverSmallObject, is64Bit ? 7 : 1);
+  // Receiver is not a small object.
+  receiverSmallObject =
+    B.CreateICmpNE(receiverSmallObject, Constant::getNullValue(intPtrTy));
+  // Ideally, we'd call objc_msgSend() here, but for now just skip the cache
+  // lookup
+
+  Value *isCacheEmpty = 
+    B.CreateICmpEQ(versionValue, Constant::getNullValue(IntTy));
+  Value *receiverNil =
+     B.CreateICmpEQ(receiver, Constant::getNullValue(receiver->getType()));
+
+  isCacheEmpty = B.CreateOr(isCacheEmpty, receiverNil);
+  isCacheEmpty = B.CreateOr(isCacheEmpty, receiverSmallObject);
+      
+  BasicBlock *cacheLookupBB = BasicBlock::Create(Context, "cache_check",
+      lookupBB->getParent());
+
+  B.CreateCondBr(isCacheEmpty, lookupBB, cacheLookupBB);
+
+  // Check the cache node is current
+  B.SetInsertPoint(cacheLookupBB);
+  Value *slotValue = B.CreateLoad(slot, "slot_value");
+  Value *slotVersion = B.CreateStructGEP(slotValue, 3);
+  // Note: Volatile load because the slot version might have changed in
+  // another thread.
+  slotVersion = B.CreateLoad(slotVersion, true, "slot_version");
+  Value *slotCachedFor = B.CreateStructGEP(slotValue, 1);
+  slotCachedFor = B.CreateLoad(slotCachedFor, true, "slot_owner");
+  Value *cls = B.CreateLoad(B.CreateBitCast(receiver, IdTy));
+  Value *isVersionCorrect = B.CreateICmpEQ(slotVersion, versionValue);
+  Value *isOwnerCorrect = B.CreateICmpEQ(slotCachedFor, cls);
+  Value *isSlotValid = B.CreateAnd(isVersionCorrect, isOwnerCorrect);
+  // If this slot is still valid, skip the lookup.
+  B.CreateCondBr(isSlotValid, afterLookupBB, lookupBB);
+
+  // Perform the real lookup and cache the result
+  removeTerminator(lookupFinishedBB);
+  // Replace the looked up slot with the loaded one
+  B.SetInsertPoint(afterLookupBB, afterLookupBB->begin());
+  PHINode *newLookup = IRBuilderCreatePHI(&B, lookup->getType(), 3, "new_lookup");
+  // Not volatile, so a redundant load elimination pass can do some phi
+  // magic with this later.
+  lookup->replaceAllUsesWith(newLookup);
+
+  B.SetInsertPoint(lookupFinishedBB);
+  Value * newReceiver = receiver;
+  if (!isSuperMessage) {
+    newReceiver = B.CreateLoad(receiverPtr);
+  }
+  BasicBlock *storeCacheBB = BasicBlock::Create(Context, "cache_store",
+      lookupBB->getParent());
+
+  // Don't store the cached lookup if we are doing forwarding tricks.
+  // Also skip caching small object messages for now
+  Value *skipCacheWrite =
+    B.CreateOr(B.CreateICmpNE(receiver, newReceiver), receiverSmallObject);
+  skipCacheWrite = B.CreateOr(skipCacheWrite, receiverNil);
+  B.CreateCondBr(skipCacheWrite, afterLookupBB, storeCacheBB);
+  B.SetInsertPoint(storeCacheBB);
+
+  // Store it even if the version is 0, because we always check that the
+  // version is not 0 at the start and an occasional redundant store is
+  // probably better than a branch every time.
+  B.CreateStore(lookup, slot);
+  B.CreateStore(B.CreateLoad(B.CreateStructGEP(lookup, 3)), version);
+  cls = B.CreateLoad(B.CreateBitCast(receiver, IdTy));
+  B.CreateStore(cls, B.CreateStructGEP(lookup, 1));
+  B.CreateBr(afterLookupBB);
+
+  newLookup->addIncoming(lookup, lookupFinishedBB);
+  newLookup->addIncoming(slotValue, cacheLookupBB);
+  newLookup->addIncoming(lookup, storeCacheBB);
+}
+
+
+void GNUstep::IMPCacher::SpeculativelyInline(Instruction *call, Function
+    *function) {
+  BasicBlock *beforeCallBB = call->getParent();
+  BasicBlock *callBB = SplitBlock(beforeCallBB, call, Owner);
+  BasicBlock *inlineBB = BasicBlock::Create(Context, "inline",
+      callBB->getParent());
+
+
+  BasicBlock::iterator iter = call;
+  iter++;
+
+  BasicBlock *afterCallBB = SplitBlock(iter->getParent(), iter, Owner);
+
+  removeTerminator(beforeCallBB);
+
+  // Put a branch before the call, testing whether the callee really is the
+  // function
+  IRBuilder<> B = IRBuilder<>(beforeCallBB);
+  Value *callee = isa<CallInst>(call) ? cast<CallInst>(call)->getCalledValue()
+      : cast<InvokeInst>(call)->getCalledValue();
+
+  const FunctionType *FTy = function->getFunctionType();
+  const FunctionType *calleeTy = cast<FunctionType>(
+      cast<PointerType>(callee->getType())->getElementType());
+  if (calleeTy != FTy) {
+    callee = B.CreateBitCast(callee, function->getType());
+  }
+
+  Value *isInlineValid = B.CreateICmpEQ(callee, function);
+  B.CreateCondBr(isInlineValid, inlineBB, callBB);
+
+  // In the inline BB, add a copy of the call, but this time calling the real
+  // version.
+  Instruction *inlineCall = call->clone();
+  Value *inlineResult= inlineCall;
+  inlineBB->getInstList().push_back(inlineCall);
+
+  B.SetInsertPoint(inlineBB);
+
+  if (calleeTy != FTy) {
+    for (unsigned i=0 ; i<FTy->getNumParams() ; i++) {
+      LLVMType *callType = calleeTy->getParamType(i);
+      LLVMType *argType = FTy->getParamType(i);
+      if (callType != argType) {
+        inlineCall->setOperand(i, new
+            BitCastInst(inlineCall->getOperand(i), argType, "", inlineCall));
+      }
+    }
+    if (FTy->getReturnType() != calleeTy->getReturnType()) {
+      if (FTy->getReturnType() == Type::getVoidTy(Context)) {
+        inlineResult = Constant::getNullValue(calleeTy->getReturnType());
+      } else {
+        inlineResult = 
+          new BitCastInst(inlineCall, calleeTy->getReturnType(), "", inlineBB);
+      }
+    }
+  }
+
+  B.CreateBr(afterCallBB);
+
+  // Unify the return values
+  if (call->getType() != Type::getVoidTy(Context)) {
+    PHINode *phi = CreatePHI(call->getType(), 2, "", afterCallBB->begin());
+    call->replaceAllUsesWith(phi);
+    phi->addIncoming(call, callBB);
+    phi->addIncoming(inlineResult, inlineBB);
+  }
+
+  // Really do the real inlining
+  InlineFunctionInfo IFI(0, 0);
+  if (CallInst *c = dyn_cast<CallInst>(inlineCall)) {
+    c->setCalledFunction(function);
+    InlineFunction(c, IFI);
+  } else if (InvokeInst *c = dyn_cast<InvokeInst>(inlineCall)) {
+    c->setCalledFunction(function);
+    InlineFunction(c, IFI);
+  }
+}
+
+CallSite GNUstep::IMPCacher::SplitSend(CallSite msgSend)
+{
+  BasicBlock *lookupBB = msgSend->getParent();
+  Function *F = lookupBB->getParent();
+  Module *M = F->getParent();
+  Function *send = M->getFunction("objc_msgSend");
+  Function *send_stret = M->getFunction("objc_msgSend_stret");
+  Function *send_fpret = M->getFunction("objc_msgSend_fpret");
+  Value *self;
+  Value *cmd;
+  int selfIndex = 0;
+  if ((msgSend.getCalledFunction() == send) ||
+      (msgSend.getCalledFunction() == send_fpret)) {
+    self = msgSend.getArgument(0);
+    cmd = msgSend.getArgument(1);
+  } else if (msgSend.getCalledFunction() == send_stret) {
+    selfIndex = 1;
+    self = msgSend.getArgument(1);
+    cmd = msgSend.getArgument(2);
+  } else {
+    abort();
+    return CallSite();
+  }
+  CGBuilder B(&F->getEntryBlock(), F->getEntryBlock().begin());
+  Value *selfPtr = B.CreateAlloca(self->getType());
+  B.SetInsertPoint(msgSend.getInstruction());
+  B.CreateStore(self, selfPtr, true);
+  LLVMType *impTy = msgSend.getCalledValue()->getType();
+  LLVMType *slotTy = PointerType::getUnqual(StructType::get(PtrTy, PtrTy, PtrTy,
+        IntTy, impTy, PtrTy, NULL));
+  Value *slot;
+  Constant *lookupFn = M->getOrInsertFunction("objc_msg_lookup_sender",
+      slotTy, selfPtr->getType(), cmd->getType(), PtrTy, NULL);
+  if (msgSend.isCall()) {
+    slot = B.CreateCall3(lookupFn, selfPtr, cmd, Constant::getNullValue(PtrTy));
+  } else {
+    InvokeInst *inv = cast<InvokeInst>(msgSend.getInstruction());
+    BasicBlock *callBB = SplitBlock(lookupBB, msgSend.getInstruction(), Owner);
+    removeTerminator(lookupBB);
+    B.SetInsertPoint(lookupBB);
+    slot = B.CreateInvoke3(lookupFn, callBB, inv->getUnwindDest(), selfPtr, cmd,
+        Constant::getNullValue(PtrTy));
+    addPredecssor(inv->getUnwindDest(), msgSend->getParent(), lookupBB);
+    B.SetInsertPoint(msgSend.getInstruction());
+  }
+  Value *imp = B.CreateLoad(B.CreateStructGEP(slot, 4));
+  msgSend.setArgument(selfIndex, B.CreateLoad(selfPtr, true));
+  msgSend.setCalledFunction(imp);
+  return CallSite(slot);
+}
+
+// Cleanly removes a terminator instruction.
+void GNUstep::removeTerminator(BasicBlock *BB) {
+  TerminatorInst *BBTerm = BB->getTerminator();
+
+  // Remove the BB as a predecessor from all of  successors
+  for (unsigned i = 0, e = BBTerm->getNumSuccessors(); i != e; ++i) {
+    BBTerm->getSuccessor(i)->removePredecessor(BB);
+  }
+
+  BBTerm->replaceAllUsesWith(UndefValue::get(BBTerm->getType()));
+  // Remove the terminator instruction itself.
+  BBTerm->eraseFromParent();
+}
+void GNUstep::addPredecssor(BasicBlock *block, BasicBlock *oldPredecessor,
+    BasicBlock *newPredecessor) {
+  for (BasicBlock::iterator i=block->begin() ; PHINode *phi=dyn_cast<PHINode>(i)
+      ; ++i) {
+    Value *v = phi->getIncomingValueForBlock(oldPredecessor);
+    phi->addIncoming(v, newPredecessor);
+  }
+}
diff --git a/third_party/libobjc/opts/IMPCacher.h b/third_party/libobjc/opts/IMPCacher.h
new file mode 100644
index 0000000000000000000000000000000000000000..28fd50086c8e601bd03d60cb23473c7309d021b9
--- /dev/null
+++ b/third_party/libobjc/opts/IMPCacher.h
@@ -0,0 +1,49 @@
+#include "LLVMCompat.h"
+#include "llvm/Support/CallSite.h"
+namespace llvm
+{
+  class BasicBlock;
+  class CallInst;
+  class Function;
+  class Instruction;
+  class IntegerType;
+  class LLVMContext;
+  class MDNode;
+  class Pass;
+  class PointerType;
+  class Value;
+}
+
+using namespace llvm;
+
+namespace GNUstep
+{
+  class IMPCacher
+  {
+    private:
+      LLVMContext &Context;
+      MDNode *AlreadyCachedFlag;
+      unsigned IMPCacheFlagKind;
+      Pass *Owner;
+      LLVMPointerType *PtrTy;
+      LLVMPointerType *IdTy;
+      LLVMIntegerType *IntTy;
+    public:
+      IMPCacher(LLVMContext &C, Pass *owner);
+      void CacheLookup(Instruction *lookup, Value *slot, Value *version, bool
+          isSuperMessage=false);
+      void SpeculativelyInline(Instruction *call, Function *function);
+      /**
+       * Turns a call to objc_msgSend*() into a call to
+       * objc_msg_lookup_sender() and a call to the resulting IMP.  The call to
+       * the IMP is returned.  The single call is faster, but prevents caching.
+       * The split call allows caching, which is faster in the best case and
+       * slower in the worst...
+       */
+      CallSite SplitSend(CallSite msgSend);
+  };
+
+  void removeTerminator(BasicBlock *BB);
+  void addPredecssor(BasicBlock *block, BasicBlock *oldPredecessor, BasicBlock
+          *newPredecessor);
+}
diff --git a/third_party/libobjc/opts/IvarPass.cpp b/third_party/libobjc/opts/IvarPass.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..648901bb38c7c448d01700d6b03f4c0a2e41682c
--- /dev/null
+++ b/third_party/libobjc/opts/IvarPass.cpp
@@ -0,0 +1,173 @@
+#include "llvm/Pass.h"
+#include "llvm/Function.h"
+#include "llvm/Module.h"
+#include "llvm/Instructions.h"
+#include "llvm/GlobalAlias.h"
+#include "llvm/GlobalVariable.h"
+#include "llvm/Constants.h"
+#include "llvm/Analysis/Verifier.h"
+#include "llvm/DefaultPasses.h"
+#include "llvm/ADT/DenseSet.h"
+#include "ObjectiveCOpts.h"
+#include <string>
+
+using namespace llvm;
+using std::string;
+
+typedef std::pair<Instruction*, Value*> Replacement;
+
+namespace llvm {
+template<> struct DenseMapInfo<Replacement> {
+  static inline Replacement getEmptyKey() { return Replacement(0,0); }
+  static inline Replacement getTombstoneKey() { return Replacement(0, (Value*)-1); }
+  static unsigned getHashValue(const Replacement& Val) { return ((uintptr_t)Val.first) * 37U; }
+  static bool isEqual(const Replacement& LHS, const Replacement& RHS) {
+    return LHS.first == RHS.first;
+  }
+};
+}
+namespace {
+  class GNUNonfragileIvarPass : public FunctionPass {
+
+    public:
+    static char ID;
+    GNUNonfragileIvarPass() : FunctionPass(ID) {}
+
+    Module *M;
+    size_t PointerSize;
+    virtual bool doInitialization(Module &Mod) {
+      M = &Mod;
+      PointerSize = 8;
+      if (M->getPointerSize() == Module::Pointer32) 
+        PointerSize = 4;
+      return false;  
+    }
+
+    std::string getSuperName(Constant *ClsStruct) {
+      User *super = cast<User>(ClsStruct->getOperand(1));
+      if (isa<ConstantPointerNull>(super)) return "";
+      GlobalVariable *name = cast<GlobalVariable>(super->getOperand(0));
+#if (LLVM_MAJOR > 3) || ((LLVM_MAJOR == 3) && (LLVM_MINOR > 0))
+      return cast<ConstantDataArray>(name->getInitializer())->getAsString();
+#else
+      return cast<ConstantArray>(name->getInitializer())->getAsString();
+#endif
+    }
+
+    size_t sizeOfClass(const std::string &className) {
+      // This is a root class
+      if ("" == className) { return 0; }
+      // These root classes are assumed to only have one ivar: isa
+      if (className.compare(0, 8, "NSObject") == 0 || 
+          className.compare(0, 6, "Object") == 0) {
+        return PointerSize;
+      }
+      GlobalVariable *Cls = M->getGlobalVariable("_OBJC_CLASS_" + className);
+      if (!Cls) return 0;
+      Constant *ClsStruct = Cls->getInitializer();
+      // Size is initialized to be negative for the non-fragile ABI.
+      ConstantInt *Size = cast<ConstantInt>(ClsStruct->getOperand(5));
+      int s = Size->getSExtValue();
+      // If we find a fragile class in the hierarchy, don't perform the
+      // simplification.  This means that we're the mixed ABI, so we need the
+      // extra indirection.
+      if (s > 0) return 0;
+      return sizeOfClass(getSuperName(ClsStruct)) - Size->getSExtValue();
+    }
+
+    size_t hardCodedOffset(const StringRef &className, 
+                           const StringRef &ivarName) {
+      GlobalVariable *Cls = M->getGlobalVariable(("_OBJC_CLASS_" + className).str(), true);
+      if (!Cls) return 0;
+      Constant *ClsStruct = Cls->getInitializer();
+      size_t superSize = sizeOfClass(getSuperName(ClsStruct));
+      if (!superSize) return 0;
+      ConstantStruct *IvarStruct = cast<ConstantStruct>(
+          cast<GlobalVariable>(ClsStruct->getOperand(6))->getInitializer());
+      int ivarCount = cast<ConstantInt>(IvarStruct->getOperand(0))->getSExtValue();
+      Constant *ivars = IvarStruct->getOperand(1);
+      for (int i=0 ; i<ivarCount ; i++) {
+        Constant *ivar = cast<Constant>(ivars->getOperand(i));
+        GlobalVariable *name =
+          cast<GlobalVariable>(
+              cast<User>(ivar->getOperand(0))->getOperand(0));
+        std::string ivarNameStr = 
+#if (LLVM_MAJOR > 3) || ((LLVM_MAJOR == 3) && (LLVM_MINOR > 0))
+          cast<ConstantDataArray>(name->getInitializer())->getAsString();
+#else
+          cast<ConstantArray>(name->getInitializer())->getAsString();
+#endif
+        // Remove the NULL terminator from the metadata string
+        ivarNameStr.resize(ivarNameStr.size() - 1);
+        if (ivarNameStr == ivarName.str())
+          return superSize +
+            cast<ConstantInt>(ivar->getOperand(2))->getSExtValue();
+      }
+      return 0;
+    }
+
+    virtual bool runOnFunction(Function &F) {
+      bool modified = false;
+      llvm::DenseSet<Replacement> replacements;
+      //llvm::cerr << "IvarPass: " << F.getName() << "\n";
+      for (Function::iterator i=F.begin(), end=F.end() ;
+          i != end ; ++i) {
+        for (BasicBlock::iterator b=i->begin(), last=i->end() ;
+            b != last ; ++b) {
+          if (LoadInst *indirectload = dyn_cast<LoadInst>(b)) {
+            if (LoadInst *load = dyn_cast<LoadInst>(indirectload->getOperand(0))) {
+              if (GlobalVariable *ivar =
+                  dyn_cast<GlobalVariable>(load->getOperand(0))) {
+                StringRef variableName = ivar->getName();
+
+                if (!variableName.startswith("__objc_ivar_offset_")) break;
+
+                static size_t prefixLength = strlen("__objc_ivar_offset_");
+
+                StringRef suffix = variableName.substr(prefixLength,
+                    variableName.size()-prefixLength);
+
+                std::pair<StringRef,StringRef> parts = suffix.split('.');
+                StringRef className = parts.first;
+                StringRef ivarName = parts.second;
+
+                // If the class, and all superclasses, are visible in this module
+                // then we can hard-code the ivar offset
+                if (size_t offset = hardCodedOffset(className, ivarName)) {
+                  replacements.insert(Replacement(indirectload,
+                              ConstantInt::get(indirectload->getType(), offset)));
+                  replacements.insert(Replacement(load, 0));
+                  modified = true;
+                } else {
+                  // If the class was compiled with the new ABI, then we have a
+                  // direct offset variable that we can use
+                  if (Value *offset = M->getGlobalVariable(
+                              ("__objc_ivar_offset_value_" + suffix).str())) {
+                    replacements.insert(Replacement(load, offset));
+                    modified = true;
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+      for (DenseSet<Replacement>::iterator i=replacements.begin(),
+              end=replacements.end() ; i != end ; ++i) {
+        if (i->second) 
+          i->first->replaceAllUsesWith(i->second);
+        i->first->removeFromParent();
+      }
+      verifyFunction(F);
+      return modified;
+    }
+  };
+
+  char GNUNonfragileIvarPass::ID = 0;
+  RegisterPass<GNUNonfragileIvarPass> X("gnu-nonfragile-ivar", "Ivar fragility pass");
+}
+
+FunctionPass *createGNUNonfragileIvarPass(void)
+{
+  return new GNUNonfragileIvarPass();
+}
diff --git a/third_party/libobjc/opts/LLVMCompat.h b/third_party/libobjc/opts/LLVMCompat.h
new file mode 100644
index 0000000000000000000000000000000000000000..85f472ceb4dc49fe3bd47a9b4bebb061f2f30389
--- /dev/null
+++ b/third_party/libobjc/opts/LLVMCompat.h
@@ -0,0 +1,144 @@
+/**
+ * Compatibility header that wraps LLVM API breakage and lets us compile with
+ * old and new versions of LLVM.
+ *
+ * First LLVM version supported is 2.9.
+ */
+
+#ifndef __LANGUAGEKIT_LLVM_HACKS__
+#define __LANGUAGEKIT_LLVM_HACKS__
+#include <llvm/Instructions.h>
+#include <llvm/Metadata.h>
+#include <llvm/Intrinsics.h>
+#include <llvm/Support/IRBuilder.h>
+
+
+// Only preserve names in a debug build.  This simplifies the
+// IR in a release build, but makes it much harder to debug.
+#ifndef DEBUG
+	typedef llvm::IRBuilder<false> CGBuilder;
+#else
+	typedef llvm::IRBuilder<> CGBuilder;
+#endif
+
+__attribute((unused)) static inline 
+llvm::PHINode* CreatePHI(llvm::Type *Ty,
+                         unsigned NumReservedValues,
+                         const llvm::Twine &NameStr="",
+                         llvm::Instruction *InsertBefore=0) {
+#if LLVM_MAJOR < 3
+    llvm::PHINode *phi = llvm::PHINode::Create(Ty, NameStr, InsertBefore);
+    phi->reserveOperandSpace(NumReservedValues);
+    return phi;
+#else
+    return llvm::PHINode::Create(Ty, NumReservedValues, NameStr, InsertBefore);
+#endif
+}
+
+__attribute((unused)) static inline 
+llvm::PHINode* IRBuilderCreatePHI(CGBuilder *Builder,
+                                  llvm::Type *Ty,
+                                  unsigned NumReservedValues,
+                                  const llvm::Twine &NameStr="")
+{
+#if LLVM_MAJOR < 3
+	llvm::PHINode *phi = Builder->CreatePHI(Ty, NameStr);
+	phi->reserveOperandSpace(NumReservedValues);
+	return phi;
+#else
+	return Builder->CreatePHI(Ty, NumReservedValues, NameStr);
+#endif
+}
+
+
+
+__attribute((unused)) static inline 
+llvm::MDNode* CreateMDNode(llvm::LLVMContext &C,
+                           llvm::Value **V,
+                            unsigned length=1) {
+#if LLVM_MAJOR < 3
+	return llvm::MDNode::get(C, V, length);
+#else
+	llvm::ArrayRef<llvm::Value*> val(V, length);
+	return llvm::MDNode::get(C, val);
+#endif
+}
+
+template<typename T>
+static inline 
+llvm::InvokeInst* IRBuilderCreateInvoke(CGBuilder *Builder,
+                                        llvm::Value *callee,
+                                        llvm::BasicBlock *dest,
+                                        llvm::BasicBlock *dest2,
+                                        T values,
+                                        const llvm::Twine &NameStr="")
+{
+#if LLVM_MAJOR < 3
+	return Builder->CreateInvoke(callee, dest, dest2, values.begin(), values.end(), NameStr);
+#else
+	return Builder->CreateInvoke(callee, dest, dest2, values, NameStr);
+#endif
+}
+
+template<typename T>
+static inline 
+llvm::CallInst* IRBuilderCreateCall(CGBuilder *Builder,
+                                    llvm::Value *callee,
+                                    T values,
+                                    const llvm::Twine &NameStr="")
+{
+#if LLVM_MAJOR < 3
+	return Builder->CreateCall(callee, values.begin(), values.end(), NameStr);
+#else
+	return Builder->CreateCall(callee, values, NameStr);
+#endif
+}
+
+template<typename T>
+static inline 
+llvm::CallInst* CreateCall(llvm::Value *callee,
+                           T values,
+                           const llvm::Twine &NameStr,
+                           llvm::Instruction *before)
+{
+#if LLVM_MAJOR < 3
+	return llvm::CallInst::Create(callee, values.begin(), values.end(), NameStr, before);
+#else
+	return llvm::CallInst::Create(callee, values, NameStr, before);
+#endif
+}
+
+
+
+#if LLVM_MAJOR < 3
+#define GetStructType(context, ...) StructType::get(context, __VA_ARGS__)
+#else
+#define GetStructType(context, ...) StructType::get(__VA_ARGS__)
+#endif
+
+__attribute((unused)) static inline 
+llvm::Constant* GetConstantStruct(llvm::LLVMContext &C, const std::vector<llvm::Constant*>
+		&V, bool Packed) {
+#if LLVM_MAJOR < 3
+	return llvm::ConstantStruct::get(C, V, Packed);
+#else
+	return llvm::ConstantStruct::getAnon(C, V, Packed);
+#endif
+}
+
+
+#if LLVM_MAJOR < 3
+typedef const llvm::Type LLVMType;
+typedef const llvm::StructType LLVMStructType;
+typedef const llvm::ArrayType LLVMArrayType;
+typedef const llvm::PointerType LLVMPointerType;
+typedef const llvm::IntegerType LLVMIntegerType;
+#else
+typedef llvm::Type LLVMType;
+typedef llvm::StructType LLVMStructType;
+typedef llvm::ArrayType LLVMArrayType;
+typedef llvm::PointerType LLVMPointerType;
+typedef llvm::IntegerType LLVMIntegerType;
+#endif
+
+#endif
diff --git a/third_party/libobjc/opts/LoopIMPCachePass.cpp b/third_party/libobjc/opts/LoopIMPCachePass.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..21fcfe1a3a2fd853c37bf3c6d0313fd55993af9d
--- /dev/null
+++ b/third_party/libobjc/opts/LoopIMPCachePass.cpp
@@ -0,0 +1,124 @@
+#include "llvm/LLVMContext.h"
+#include "llvm/Pass.h"
+#include "llvm/Function.h"
+#include "llvm/Module.h"
+#include "llvm/Instructions.h"
+#include "llvm/Constants.h"
+#include "llvm/Support/IRBuilder.h"
+#include "llvm/Analysis/LoopInfo.h"
+#include "llvm/Analysis/Verifier.h"
+#include "llvm/DefaultPasses.h"
+#include "ObjectiveCOpts.h"
+#include "IMPCacher.h"
+#include <string>
+
+using namespace GNUstep;
+using namespace llvm;
+using std::string;
+
+namespace 
+{
+  class GNULoopIMPCachePass : public FunctionPass 
+  {
+    GNUstep::IMPCacher *cacher;
+    LLVMIntegerType *IntTy;
+    Module *M;
+    bool skip;
+    Function *sendFn;
+    Function *lookupFn;
+    Function *send_stretFn;
+    Function *send_fpretFn;
+
+    public:
+    static char ID;
+    GNULoopIMPCachePass() : FunctionPass(ID) {}
+    ~GNULoopIMPCachePass() { delete cacher; }
+
+    virtual bool doInitialization(Module &Mod) {
+      cacher = new GNUstep::IMPCacher(Mod.getContext(), this);
+      IntTy = (sizeof(int) == 4 ) ? Type::getInt32Ty(Mod.getContext()) :
+          Type::getInt64Ty(Mod.getContext()) ;
+      M = &Mod;
+      skip = false;
+      sendFn = M->getFunction("objc_msgSend");
+      send_stretFn = M->getFunction("objc_msgSend_stret");
+      send_fpretFn = M->getFunction("objc_msgSend_fpret");
+      lookupFn =M->getFunction("objc_msg_lookup_sender");
+      // If this module doesn't contain any message sends, then skip it
+      if ((sendFn == 0) && (send_stretFn == 0) && (send_fpretFn == 0) &&
+          (lookupFn ==0)) {
+        skip = true;
+      }
+      return false;  
+    }
+
+    virtual void getAnalysisUsage(AnalysisUsage &Info) const {
+      Info.addRequired<LoopInfo>();
+    }
+
+
+    virtual bool runOnFunction(Function &F) {
+      if (skip) { return false; }
+      LoopInfo &LI = getAnalysis<LoopInfo>();
+      bool modified = false;
+      SmallVector<CallSite, 16> Lookups;
+      SmallVector<CallSite, 16> Sends;
+      BasicBlock *entry = &F.getEntryBlock();
+
+      for (Function::iterator i=F.begin(), end=F.end() ;
+          i != end ; ++i) {
+        // Ignore basic blocks that are not parts of loops.
+        if (LI.getLoopDepth(i) == 0) { continue; }
+        for (BasicBlock::iterator b=i->begin(), last=i->end() ;
+            b != last ; ++b) {
+          CallSite call = CallSite(b);
+          if (CallSite() != call) {
+            Value *callee = call.getCalledValue()->stripPointerCasts();
+            Function *func = dyn_cast<Function>(callee);
+            if (func) {
+              if (func == lookupFn) {
+                modified = true;
+                Lookups.push_back(call);
+              } else if ((func == sendFn) || (func == send_fpretFn) ||
+                         (func == send_stretFn)) {
+                modified = true;
+                Sends.push_back(call);
+              }
+            }
+          }
+        }
+      }
+      for (SmallVectorImpl<CallSite>::iterator i=Sends.begin(), 
+          e=Sends.end() ; e!=i ; i++) {
+        Lookups.push_back(cacher->SplitSend(*i));
+      }
+      IRBuilder<> B = IRBuilder<>(entry);
+      for (SmallVectorImpl<CallSite>::iterator i=Lookups.begin(), 
+          e=Lookups.end() ; e!=i ; i++) {
+        LLVMType *SlotPtrTy = (*i)->getType();
+        B.SetInsertPoint(entry, entry->begin());
+        Value *slot = B.CreateAlloca(SlotPtrTy, 0, "slot");
+        Value *version = B.CreateAlloca(IntTy, 0, "slot_version");
+
+        B.CreateStore(Constant::getNullValue(SlotPtrTy), slot);
+        B.CreateStore(Constant::getNullValue(IntTy), version);
+        cacher->CacheLookup(i->getInstruction(), slot, version);
+      }
+#ifdef DEBUG
+      if (modified){
+        verifyFunction(F);
+      }
+#endif
+      return modified;
+    }
+  };
+
+  char GNULoopIMPCachePass::ID = 0;
+  RegisterPass<GNULoopIMPCachePass> X("gnu-loop-imp-cache", 
+          "Cache IMPs in loops pass");
+}
+
+FunctionPass *createGNULoopIMPCachePass(void)
+{
+  return new GNULoopIMPCachePass();
+}
diff --git a/third_party/libobjc/opts/ObjectiveCOpts.cpp b/third_party/libobjc/opts/ObjectiveCOpts.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9cc64048a9d9ea509c61ca6f59dbe908582d352c
--- /dev/null
+++ b/third_party/libobjc/opts/ObjectiveCOpts.cpp
@@ -0,0 +1,92 @@
+#include "llvm/Pass.h"
+#include "llvm/Module.h"
+#if LLVM_MAJOR >= 3
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/PassManager.h"
+#endif
+
+#include "ObjectiveCOpts.h"
+
+using namespace llvm;
+
+namespace 
+{
+  class ObjectiveCOpts : public ModulePass {
+    ModulePass *ClassIMPCachePass;
+    ModulePass *ClassLookupCachePass;
+    ModulePass *ClassMethodInliner;
+    FunctionPass *GNUNonfragileIvarPass;
+    FunctionPass *GNULoopIMPCachePass;
+
+    public:
+    static char ID;
+    ObjectiveCOpts() : ModulePass(ID) {
+      ClassIMPCachePass = createClassIMPCachePass();
+      ClassLookupCachePass = createClassLookupCachePass();
+      ClassMethodInliner = createClassMethodInliner();
+      GNUNonfragileIvarPass = createGNUNonfragileIvarPass();
+      GNULoopIMPCachePass = createGNULoopIMPCachePass();
+    }
+    virtual ~ObjectiveCOpts() {
+      delete ClassIMPCachePass;
+      delete ClassMethodInliner;
+      delete ClassLookupCachePass;
+      delete GNULoopIMPCachePass;
+      delete GNUNonfragileIvarPass;
+    }
+
+    virtual bool runOnModule(Module &Mod) {
+      bool modified;
+      modified = ClassIMPCachePass->runOnModule(Mod);
+      modified |= ClassLookupCachePass->runOnModule(Mod);
+      modified |= ClassMethodInliner->runOnModule(Mod);
+
+      for (Module::iterator F=Mod.begin(), fend=Mod.end() ;
+          F != fend ; ++F) {
+
+        if (F->isDeclaration()) { continue; }
+        modified |= GNUNonfragileIvarPass->runOnFunction(*F);
+        modified |= GNULoopIMPCachePass->runOnFunction(*F);
+      }
+
+      return modified;
+    };
+  };
+
+  char ObjectiveCOpts::ID = 0;
+  RegisterPass<ObjectiveCOpts> X("gnu-objc", 
+          "Run all of the GNUstep Objective-C runtimm optimisations");
+
+
+#if LLVM_MAJOR >= 3
+
+  void addObjCPasses(const PassManagerBuilder &Builder, PassManagerBase &PM) {
+    // Always add the ivar simplification pass
+    PM.add(createGNUNonfragileIvarPass());
+    // Only cache IMPs in loops if we're not optimising for size.
+    if (Builder.SizeLevel == 0) {
+      PM.add(createGNULoopIMPCachePass());
+    }
+    // Do the rest of the caching if we're not aggressively optimising for size
+    if (Builder.SizeLevel < 2) {
+      PM.add(createClassIMPCachePass());
+      PM.add(createClassLookupCachePass());
+    }
+    // Definitely don't do extra inlining if we're optimising for size!
+    if (Builder.SizeLevel == 0) {
+      PM.add(createClassMethodInliner());
+    }
+  }
+  /*
+  static struct PluginRegister {
+    PluginRegister() {
+      PassManagerBuilder::addGlobalExtension(PassManagerBuilder::EP_LoopOptimizerEnd,
+                                                   addObjCPasses);
+    }
+  } Register;
+  */
+  RegisterStandardPasses S(PassManagerBuilder::EP_LoopOptimizerEnd,
+                           addObjCPasses);
+#endif
+
+}
diff --git a/third_party/libobjc/opts/ObjectiveCOpts.h b/third_party/libobjc/opts/ObjectiveCOpts.h
new file mode 100644
index 0000000000000000000000000000000000000000..c90452d2757778a3bf7bbd3d1ab03d7fa733a5c2
--- /dev/null
+++ b/third_party/libobjc/opts/ObjectiveCOpts.h
@@ -0,0 +1,7 @@
+llvm::ModulePass *createClassIMPCachePass(void);
+llvm::ModulePass *createClassLookupCachePass(void);
+llvm::ModulePass *createClassMethodInliner(void);
+llvm::FunctionPass *createGNUNonfragileIvarPass(void);
+llvm::FunctionPass *createGNULoopIMPCachePass(void);
+llvm::ModulePass *createTypeFeedbackPass(void);
+llvm::ModulePass *createTypeFeedbackDrivenInlinerPass(void);
diff --git a/third_party/libobjc/opts/README b/third_party/libobjc/opts/README
new file mode 100644
index 0000000000000000000000000000000000000000..9a646ad568684ac8e026c1e9bb38d3a479b360e6
--- /dev/null
+++ b/third_party/libobjc/opts/README
@@ -0,0 +1,30 @@
+GNUstep Runtime Optimisations
+=============================
+
+This directory contains LLVM optimisations specific to libobjc2.  To build
+them, you must copy this directory to llvm/lib/Transforms/GNURuntime (where
+llvm is the root of your llvm checkout).
+
+Running GNU make will then create GNUObjCRuntime.so.  This library can be
+passed to opt to run optimisations on bitcode generated with clang or
+LanguageKit.
+
+Non-Fragile Ivar Pass
+---------------------
+
+Running `opt -gnu-nonfragile-ivar` will invoke the non-fragile instance
+variable lowering pass.  This will turn non-fragile instance variable accesses,
+which go via one or two indirection layers, into more fragile ones.  If a class
+and all of its superclasses are present in the module then this pass will turn
+indirect instance variable accesses into hard-coded ones.
+
+For this pass to be most useful, it should be run as a link-time optimisation.
+
+Type Feedback
+-------------
+
+Running `opt -gnu-objc-type-feedback` enables type feedback.  Objective-C
+message lookups will be replaced by calls to the profiling version in the
+runtime library.  The generated data can then be used for future optimisations
+(speculative inlining, polymorphic inline caching, and so on), which have not
+yet been written.
diff --git a/third_party/libobjc/opts/TypeFeedback.cpp b/third_party/libobjc/opts/TypeFeedback.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8c940ef54f299d1c3387475bd9a3f1cfe84c2df6
--- /dev/null
+++ b/third_party/libobjc/opts/TypeFeedback.cpp
@@ -0,0 +1,152 @@
+#include "llvm/Constants.h"
+#include "llvm/Pass.h"
+#include "llvm/Module.h"
+#include "llvm/Function.h"
+#include "llvm/Instructions.h"
+#include "llvm/Support/CallSite.h"
+#include "llvm/Support/IRBuilder.h"
+#include "llvm/Linker.h"
+#include <vector>
+
+using namespace llvm;
+#include "LLVMCompat.h"
+
+namespace {
+  struct GNUObjCTypeFeedback : public ModulePass {
+      
+    typedef std::pair<CallInst*,CallInst*> callPair;
+    typedef std::vector<callPair > replacementVector;
+      static char ID;
+    uint32_t callsiteCount;
+    LLVMIntegerType *Int32Ty;
+      GNUObjCTypeFeedback() : ModulePass(ID), callsiteCount(0) {}
+
+    void profileFunction(Function &F, Constant *ModuleID) {
+      for (Function::iterator i=F.begin(), e=F.end() ;
+                      i != e ; ++i) {
+
+        Module *M = F.getParent();
+        replacementVector replacements;
+        for (BasicBlock::iterator b=i->begin(), last=i->end() ;
+            b != last ; ++b) {
+
+          CallSite call(b);
+          if (call.getInstruction() && !call.getCalledFunction()) {
+            llvm::SmallVector<llvm::Value*, 4> args;
+            args.push_back(call->getOperand(1));
+            args.push_back(call->getOperand(0)),
+            args.push_back(ModuleID);
+            args.push_back(ConstantInt::get(Int32Ty, callsiteCount++));
+            Constant *profile = 
+                M->getOrInsertFunction("objc_msg_profile",
+                  Type::getVoidTy(M->getContext()),
+                  args[0]->getType(), args[1]->getType(),
+                  args[2]->getType(), args[3]->getType(), NULL);
+            CreateCall(profile, args, "", call.getInstruction());
+          }
+        }
+      }
+    }
+
+    public:
+    virtual bool runOnModule(Module &M)
+    {
+      LLVMContext &VMContext = M.getContext();
+      Int32Ty = IntegerType::get(VMContext, 32);
+      LLVMPointerType *PtrTy = Type::getInt8PtrTy(VMContext);
+      Constant *moduleName = 
+#if (LLVM_MAJOR > 3) || ((LLVM_MAJOR == 3) && (LLVM_MINOR > 0))
+        ConstantDataArray::getString(VMContext, M.getModuleIdentifier(), true);
+#else
+        ConstantArray::get(VMContext, M.getModuleIdentifier(), true);
+#endif
+      moduleName = new GlobalVariable(M, moduleName->getType(), true,
+          GlobalValue::InternalLinkage, moduleName,
+          ".objc_profile_module_name");
+      std::vector<Constant*> functions;
+
+      llvm::Constant *Zeros[2];
+      Zeros[0] = ConstantInt::get(Type::getInt32Ty(VMContext), 0);
+      Zeros[1] = Zeros[0];
+
+      moduleName = ConstantExpr::getGetElementPtr(moduleName, Zeros, 2);
+      functions.push_back(moduleName);;
+      functions.push_back(moduleName);;
+
+      for (Module::iterator F=M.begin(), e=M.end() ;
+        F != e ; ++F) {
+        if (F->isDeclaration()) { continue; }
+        functions.push_back(ConstantExpr::getBitCast(F, PtrTy));
+
+        Constant * ConstStr = 
+#if (LLVM_MAJOR > 3) || ((LLVM_MAJOR == 3) && (LLVM_MINOR > 0))
+          llvm::ConstantDataArray::getString(VMContext, F->getName(), true);
+#else
+          llvm::ConstantArray::get(VMContext, F->getName());
+#endif
+        ConstStr = new GlobalVariable(M, ConstStr->getType(), true,
+            GlobalValue::PrivateLinkage, ConstStr, "str");
+        functions.push_back(
+            ConstantExpr::getGetElementPtr(ConstStr, Zeros, 2));
+
+        profileFunction(*F, moduleName);
+      }
+      functions.push_back(ConstantPointerNull::get(PtrTy));
+      Constant *symtab = ConstantArray::get(ArrayType::get(PtrTy,
+            functions.size()), functions);
+      Value *symbolTable = new GlobalVariable(M, symtab->getType(), true,
+          GlobalValue::InternalLinkage, symtab, "symtab");
+
+      Function *init =
+        Function::Create(FunctionType::get(Type::getVoidTy(VMContext), false),
+            GlobalValue::PrivateLinkage, "load_symbol_table", &M);
+      BasicBlock * EntryBB = BasicBlock::Create(VMContext, "entry", init);
+      IRBuilder<> B = IRBuilder<>(EntryBB);
+      Value *syms = B.CreateStructGEP(symbolTable, 0);
+      B.CreateCall(M.getOrInsertFunction("objc_profile_write_symbols",
+            Type::getVoidTy(VMContext), syms->getType(), NULL),
+          syms);
+      B.CreateRetVoid();
+
+      GlobalVariable *GCL = M.getGlobalVariable("llvm.global_ctors");
+
+      std::vector<Constant*> ctors;
+
+      ConstantArray *CA = cast<ConstantArray>(GCL->getInitializer());
+
+      for (User::op_iterator i = CA->op_begin(), e = CA->op_end(); i != e; ++i) {
+        ctors.push_back(cast<ConstantStruct>(*i));
+      }
+
+      // Type of one ctor
+      LLVMType *ctorTy =
+        cast<ArrayType>(GCL->getType()->getElementType())->getElementType();
+      // Add the 
+      std::vector<Constant*> CSVals;
+      CSVals.push_back(ConstantInt::get(Type::getInt32Ty(VMContext),65535));
+      CSVals.push_back(init);
+      ctors.push_back(GetConstantStruct(GCL->getContext(), CSVals, false));
+      // Create the array initializer.
+      CA = cast<ConstantArray>(ConstantArray::get(ArrayType::get(ctorTy,
+            ctors.size()), ctors));
+      // Create the new global and replace the old one
+      GlobalVariable *NGV = new GlobalVariable(CA->getType(),
+          GCL->isConstant(), GCL->getLinkage(), CA, "", GCL->isThreadLocal());
+      GCL->getParent()->getGlobalList().insert(GCL, NGV);
+      NGV->takeName(GCL);
+      GCL->replaceAllUsesWith(NGV);
+      GCL->eraseFromParent();
+
+      return true;
+    }
+
+  };
+  
+  char GNUObjCTypeFeedback::ID = 0;
+  RegisterPass<GNUObjCTypeFeedback> X("gnu-objc-type-feedback", 
+      "Objective-C type feedback for the GNU runtime.", false, true);
+}
+
+ModulePass *createTypeFeedbackPass(void) {
+  return new GNUObjCTypeFeedback();
+}
diff --git a/third_party/libobjc/opts/TypeFeedbackDrivenInliner.cpp b/third_party/libobjc/opts/TypeFeedbackDrivenInliner.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a189f03c2b83c9da61588083b2ac45b00945da3e
--- /dev/null
+++ b/third_party/libobjc/opts/TypeFeedbackDrivenInliner.cpp
@@ -0,0 +1,99 @@
+#include "llvm/Constants.h"
+#include "llvm/Pass.h"
+#include "llvm/Module.h"
+#include "llvm/Function.h"
+#include "llvm/Instructions.h"
+#include "llvm/Support/IRBuilder.h"
+#include "llvm/Analysis/InlineCost.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/Linker.h"
+#include <vector>
+#include "TypeInfoProvider.h"
+
+using namespace llvm;
+using namespace GNUstep;
+
+namespace {
+  struct GNUObjCTypeFeedbackDrivenInliner : public ModulePass {
+      
+    typedef std::pair<CallInst*,CallInst*> callPair;
+    typedef std::vector<callPair > replacementVector;
+      static char ID;
+    uint32_t callsiteCount;
+    const IntegerType *Int32Ty;
+
+
+    public:
+
+    GNUObjCTypeFeedbackDrivenInliner() : ModulePass(ID), callsiteCount(0) {}
+
+    virtual bool runOnModule(Module &M)
+    {
+      bool modified = false;
+      LLVMContext &VMContext = M.getContext();
+      Int32Ty = IntegerType::get(VMContext, 32);
+      TypeInfoProvider::CallSiteMap *SiteMap =
+        TypeInfoProvider::SharedTypeInfoProvider()->getCallSitesForModule(M);
+      SmallPtrSet<const Function *, 16> NeverInline;
+
+      //TypeInfoProvider::SharedTypeInfoProvider()->PrintStatistics();
+      GNUstep::IMPCacher cacher = GNUstep::IMPCacher(M.getContext(), this);
+      InlineCostAnalyzer CA;
+      SmallVector<CallSite, 16> messages;
+
+      for (Module::iterator F=M.begin(), fend=M.end() ;
+          F != fend ; ++F) {
+
+
+        if (F->isDeclaration()) { continue; }
+
+        for (Function::iterator i=F->begin(), end=F->end() ;
+            i != end ; ++i) {
+          for (BasicBlock::iterator b=i->begin(), last=i->end() ;
+              b != last ; ++b) {
+            CallSite call(b);
+            if (call.getInstruction() && !call.getCalledFunction()) {
+              messages.push_back(call);
+            }
+          }
+        }
+      }
+      TypeInfoProvider::CallSiteMap::iterator Entry = SiteMap->begin();
+
+      for (SmallVectorImpl<CallSite>::iterator i=messages.begin(), 
+          e=messages.end() ; e!=i ; ++i, ++Entry) {
+
+        if (Entry->size() == 1) {
+
+          Function *method = M.getFunction(Entry->begin()->getKey());
+          if (0 == method || method->isDeclaration()) { continue; }
+
+#if (LLVM_MAJOR > 3) || ((LLVM_MAJOR == 3) && (LLVM_MINOR > 0))
+          InlineCost IC = CA.getInlineCost((*i), method, 200);
+#else
+          InlineCost IC = CA.getInlineCost((*i), method, NeverInline);
+#define getCost getValue
+#endif
+          // FIXME: 200 is a random number.  Pick a better one!
+          if (IC.isAlways() || (IC.isVariable() && IC.getCost() < 200)) {
+            cacher.SpeculativelyInline((*i).getInstruction(), method);
+            modified = true;
+          }
+        }
+        // FIXME: Inline the most popular call if one is much more popular
+        // than the others.
+      }
+      return modified;
+    }
+
+  };
+  
+  char GNUObjCTypeFeedbackDrivenInliner::ID = 0;
+  RegisterPass<GNUObjCTypeFeedbackDrivenInliner> X("gnu-objc-feedback-driven-inline", 
+      "Objective-C type feedback-driven inliner for the GNU runtime.", false,
+      true);
+}
+
+ModulePass *createTypeFeedbackDrivenInlinerPass(void) {
+  return new GNUObjCTypeFeedbackDrivenInliner();
+}
diff --git a/third_party/libobjc/opts/TypeInfoProvider.h b/third_party/libobjc/opts/TypeInfoProvider.h
new file mode 100644
index 0000000000000000000000000000000000000000..cd659bf3c773ceab09638e3f84e75f856f0109f9
--- /dev/null
+++ b/third_party/libobjc/opts/TypeInfoProvider.h
@@ -0,0 +1,45 @@
+#include "IMPCacher.h"
+#include "llvm/Pass.h"
+#include "llvm/Function.h"
+#include "llvm/Module.h"
+#include "llvm/Instructions.h"
+#include "llvm/Constants.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/Metadata.h"
+#include "llvm/Support/IRBuilder.h"
+#include "llvm/Support/CallSite.h"
+#include "llvm/Transforms/Utils/BasicBlockUtils.h"
+#include "llvm/Transforms/Utils/Cloning.h"
+#include "llvm/ADT/StringMap.h"
+
+using namespace llvm;
+namespace GNUstep
+{
+  class TypeInfoProvider
+  {
+    public:
+      typedef StringMap<uintptr_t> CallSiteEntry;
+      //typedef std::vector<CallSiteEntry> CallSiteMap;
+      typedef SmallVector<CallSiteEntry, 16> CallSiteMap;
+    private:
+      struct callsite_info
+      {
+        uintptr_t moduleID;
+        int32_t callsiteID;
+        uintptr_t methodID;
+      };
+      const char *symbol_table;
+      size_t symbol_size;
+      StringMap<CallSiteMap> CallSiteRecords;
+
+      void loadCallsiteRecords(callsite_info *callsite_records, size_t size);
+      TypeInfoProvider(void);
+
+    public:
+      CallSiteMap* getCallSitesForModule(Module &M);
+      void PrintStatistics();
+      static TypeInfoProvider* SharedTypeInfoProvider();
+      ~TypeInfoProvider();
+  };
+
+}
diff --git a/third_party/libobjc/pool.h b/third_party/libobjc/pool.h
new file mode 100644
index 0000000000000000000000000000000000000000..ffa8a6ad7cd27e718a33664d62e43e73c41cb031
--- /dev/null
+++ b/third_party/libobjc/pool.h
@@ -0,0 +1,53 @@
+#include <stdlib.h>
+#include "lock.h"
+
+#ifndef POOL_TYPE
+#error POOL_TYPE must be defined
+#endif
+#ifndef POOL_TYPE
+#error POOL_NAME must be defined
+#endif
+
+// Horrible multiple indirection to satisfy the weird precedence rules in cpp
+#define REALLY_PREFIX_SUFFIX(x,y) x ## y
+#define PREFIX_SUFFIX(x, y) REALLY_PREFIX_SUFFIX(x, y)
+#define NAME(x) PREFIX_SUFFIX(POOL_NAME, x)
+
+#define PAGE_SIZE 4096
+
+// Malloc one page at a time.
+#define POOL_SIZE ((PAGE_SIZE) / sizeof(POOL_TYPE))
+static POOL_TYPE* NAME(_pool);
+static int NAME(_pool_next_index) = -1;
+
+#ifdef THREAD_SAFE_POOL
+static mutex_t NAME(_lock);
+#define LOCK_POOL() LOCK(&POOL_NAME##_lock)
+#define UNLOCK_POOL() LOCK(&POOL_NAME##_lock)
+#else
+#define LOCK_POOL()
+#define UNLOCK_POOL()
+#endif
+
+static inline POOL_TYPE*NAME(_pool_alloc)(void)
+{
+	LOCK_POOL();
+	if (0 > NAME(_pool_next_index))
+	{
+		NAME(_pool) = malloc(PAGE_SIZE);
+		NAME(_pool_next_index) = POOL_SIZE - 1;
+	}
+	POOL_TYPE* new = &NAME(_pool)[NAME(_pool_next_index)--];
+	UNLOCK_POOL();
+	return new;
+}
+#undef NAME
+#undef POOL_SIZE
+#undef PAGE_SIZE
+#undef POOL_NAME
+#undef POOL_TYPE
+#undef LOCK_POOL
+#undef UNLOCK_POOL
+#ifdef THREAD_SAFE_POOL
+#undef THREAD_SAFE_POOL
+#endif
diff --git a/third_party/libobjc/properties.h b/third_party/libobjc/properties.h
new file mode 100644
index 0000000000000000000000000000000000000000..9500ac56eec51948852ec070be0279ee9f78091b
--- /dev/null
+++ b/third_party/libobjc/properties.h
@@ -0,0 +1,105 @@
+#include "visibility.h"
+
+enum PropertyAttributeKind 
+{
+	/**
+	 * Property has no attributes.
+	 */
+	OBJC_PR_noattr    = 0x00,
+	/**
+	 * The property is declared read-only.
+	 */
+	OBJC_PR_readonly  = (1<<0),
+	/**
+	 * The property has a getter.
+	 */
+	OBJC_PR_getter    = (1<<1),
+	/**
+	 * The property has assign semantics.
+	 */
+	OBJC_PR_assign    = (1<<2),
+	/**
+	 * The property is declared read-write.
+	 */
+	OBJC_PR_readwrite = (1<<3),
+	/**
+	 * Property has retain semantics.
+	 */
+	OBJC_PR_retain    = (1<<4),
+	/**
+	 * Property has copy semantics.
+	 */
+	OBJC_PR_copy      = (1<<5),
+	/**
+	 * Property is marked as non-atomic.
+	 */
+	OBJC_PR_nonatomic = (1<<6),
+	/**
+	 * Property has setter.
+	 */
+	OBJC_PR_setter    = (1<<7)
+};
+
+/**
+ * Structure used for property enumeration.  Note that property enumeration is
+ * currently quite broken on OS X, so achieving full compatibility there is
+ * impossible.  Instead, we strive to achieve compatibility with the
+ * documentation.
+ */
+struct objc_property
+{
+	/**
+	 * Name of this property.
+	 */
+	const char *name;
+	/**
+	 * Attributes for this property.  Made by ORing together
+	 * PropertyAttributeKinds.
+	 */
+	char attributes;
+	/**
+	 * Flag set if the property is synthesized.
+	 */
+	const char isSynthesized;
+	/**
+	 * Name of the getter for this property.
+	 */
+	const char *getter_name;
+	/**
+	 * Type encoding for the get method for this property.
+	 */
+	const char *getter_types;
+	/**
+	 * Name of the set method for this property.
+	 */
+	const char *setter_name;
+	/**
+	 * Type encoding of the setter for this property.
+	 */
+	const char *setter_types;
+};
+
+/**
+ * List of property inrospection data.
+ */
+struct objc_property_list
+{
+	/**
+	 * Number of properties in this array.
+	 */
+	int count;
+	/* 
+	 * The next property in a linked list.
+	 */
+	struct objc_property_list *next; 
+	/**
+	 * List of properties.
+	 */
+	struct objc_property properties[];
+};
+
+/**
+ * Constructs a property description from a list of attributes.
+ */
+PRIVATE struct objc_property propertyFromAttrs(const objc_property_attribute_t *attributes,
+                                               unsigned int attributeCount);
diff --git a/third_party/libobjc/properties.m b/third_party/libobjc/properties.m
new file mode 100644
index 0000000000000000000000000000000000000000..fe4344d996bf187564f7320bdb3ed5521c455ffd
--- /dev/null
+++ b/third_party/libobjc/properties.m
@@ -0,0 +1,532 @@
+#include "objc/runtime.h"
+#include "objc/objc-arc.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "class.h"
+#include "properties.h"
+#include "spinlock.h"
+#include "visibility.h"
+#include "nsobject.h"
+#include "gc_ops.h"
+#include "lock.h"
+
+PRIVATE int spinlocks[spinlock_count];
+
+/**
+ * Public function for getting a property.  
+ */
+id objc_getProperty(id obj, SEL _cmd, ptrdiff_t offset, BOOL isAtomic)
+{
+	if (nil == obj) { return nil; }
+	char *addr = (char*)obj;
+	addr += offset;
+	if (isGCEnabled)
+	{
+		return *(id*)addr;
+	}
+	id ret;
+	if (isAtomic)
+	{
+		volatile int *lock = lock_for_pointer(addr);
+		lock_spinlock(lock);
+		ret = *(id*)addr;
+		ret = objc_retain(ret);
+		unlock_spinlock(lock);
+		ret = objc_autoreleaseReturnValue(ret);
+	}
+	else
+	{
+		ret = *(id*)addr;
+		ret = objc_retainAutoreleaseReturnValue(ret);
+	}
+	return ret;
+}
+
+void objc_setProperty(id obj, SEL _cmd, ptrdiff_t offset, id arg, BOOL isAtomic, BOOL isCopy)
+{
+	if (nil == obj) { return; }
+	char *addr = (char*)obj;
+	addr += offset;
+
+	if (isGCEnabled)
+	{
+		if (isCopy)
+		{
+			arg = [arg copy];
+		}
+		*(id*)addr = arg;
+		return;
+	}
+	if (isCopy)
+	{
+		arg = [arg copy];
+	}
+	else
+	{
+		arg = objc_retain(arg);
+	}
+	id old;
+	if (isAtomic)
+	{
+		volatile int *lock = lock_for_pointer(addr);
+		lock_spinlock(lock);
+		old = *(id*)addr;
+		*(id*)addr = arg;
+		unlock_spinlock(lock);
+	}
+	else
+	{
+		old = *(id*)addr;
+		*(id*)addr = arg;
+	}
+	objc_release(old);
+}
+
+/**
+ * Structure copy function.  This is provided for compatibility with the Apple
+ * APIs (it's an ABI function, so it's semi-public), but it's a bad design so
+ * it's not used.  The problem is that it does not identify which of the
+ * pointers corresponds to the object, which causes some excessive locking to
+ * be needed.
+ */
+void objc_copyPropertyStruct(void *dest,
+                             void *src,
+                             ptrdiff_t size,
+                             BOOL atomic,
+                             BOOL strong)
+{
+	if (atomic)
+	{
+		volatile int *lock = lock_for_pointer(src);
+		volatile int *lock2 = lock_for_pointer(src);
+		lock_spinlock(lock);
+		lock_spinlock(lock2);
+		memcpy(dest, src, size);
+		unlock_spinlock(lock);
+		unlock_spinlock(lock2);
+	}
+	else
+	{
+		memcpy(dest, src, size);
+	}
+}
+
+/**
+ * Get property structure function.  Copies a structure from an ivar to another
+ * variable.  Locks on the address of src.
+ */
+void objc_getPropertyStruct(void *dest,
+                            void *src,
+                            ptrdiff_t size,
+                            BOOL atomic,
+                            BOOL strong)
+{
+	if (atomic)
+	{
+		volatile int *lock = lock_for_pointer(src);
+		lock_spinlock(lock);
+		memcpy(dest, src, size);
+		unlock_spinlock(lock);
+	}
+	else
+	{
+		memcpy(dest, src, size);
+	}
+}
+
+/**
+ * Set property structure function.  Copes a structure to an ivar.  Locks on
+ * dest.
+ */
+void objc_setPropertyStruct(void *dest,
+                            void *src,
+                            ptrdiff_t size,
+                            BOOL atomic,
+                            BOOL strong)
+{
+	if (atomic)
+	{
+		volatile int *lock = lock_for_pointer(dest);
+		lock_spinlock(lock);
+		memcpy(dest, src, size);
+		unlock_spinlock(lock);
+	}
+	else
+	{
+		memcpy(dest, src, size);
+	}
+}
+
+
+objc_property_t class_getProperty(Class cls, const char *name)
+{
+	// Old ABI classes don't have declared properties
+	if (Nil == cls || !objc_test_class_flag(cls, objc_class_flag_new_abi))
+	{
+		return NULL;
+	}
+	struct objc_property_list *properties = cls->properties;
+	while (NULL != properties)
+	{
+		for (int i=0 ; i<properties->count ; i++)
+		{
+			objc_property_t p = &properties->properties[i];
+			if (strcmp(p->name, name) == 0)
+			{
+				return p;
+			}
+		}
+		properties = properties->next;
+	}
+	return NULL;
+}
+
+objc_property_t* class_copyPropertyList(Class cls, unsigned int *outCount)
+{
+	if (Nil == cls || !objc_test_class_flag(cls, objc_class_flag_new_abi))
+	{
+		if (NULL != outCount) { *outCount = 0; }
+		return NULL;
+	}
+	struct objc_property_list *properties = cls->properties;
+	unsigned int count = 0;
+	for (struct objc_property_list *l=properties ; NULL!=l ; l=l->next)
+	{
+		count += l->count;
+	}
+	if (NULL != outCount)
+	{
+		*outCount = count;
+	}
+	if (0 == count)
+	{
+		return NULL;
+	}
+	objc_property_t *list = calloc(sizeof(objc_property_t), count);
+	unsigned int out = 0;
+	for (struct objc_property_list *l=properties ; NULL!=l ; l=l->next)
+	{
+		for (int i=0 ; i<properties->count ; i++)
+		{
+			list[out] = &l->properties[i];
+		}
+	}
+	return list;
+}
+
+const char *property_getName(objc_property_t property)
+{
+	if (NULL == property) { return NULL; }
+
+	const char *name = property->name;
+	if (name[0] == 0)
+	{
+		name += name[1];
+	}
+	return name;
+}
+
+PRIVATE size_t lengthOfTypeEncoding(const char *types);
+
+/**
+ * The compiler stores the type encoding of the getter.  We replace this with
+ * the type encoding of the property itself.  We use a 0 byte at the start to
+ * indicate that the swap has taken place.
+ */
+static const char *property_getTypeEncoding(objc_property_t property)
+{
+	if (NULL == property) { return NULL; }
+
+	const char *name = property->getter_types;
+	if (name[0] == 0)
+	{
+		return &name[1];
+	}
+	size_t typeSize = lengthOfTypeEncoding(name);
+	char *buffer = malloc(typeSize + 2);
+	buffer[0] = 0;
+	memcpy(buffer+1, name, typeSize);
+	buffer[typeSize+1] = 0;
+	if (!__sync_bool_compare_and_swap(&(property->getter_types), name, buffer))
+	{
+		free(buffer);
+	}
+	return &property->getter_types[1];
+}
+
+const char *property_getAttributes(objc_property_t property)
+{
+	if (NULL == property) { return NULL; }
+
+	const char *name = (char*)property->name;
+	if (name[0] == 0)
+	{
+		return name + 2;
+	}
+
+	const char *typeEncoding = property_getTypeEncoding(property);
+	size_t typeSize = strlen(typeEncoding);
+	size_t nameSize = strlen(property->name);
+	// Encoding is T{type},V{name}, so 4 bytes for the "T,V" that we always
+	// need.  We also need two bytes for the leading null and the length.
+	size_t encodingSize = typeSize + nameSize + 6;
+	char flags[16];
+	size_t i = 0;
+	// Flags that are a comma then a character
+	if ((property->attributes & OBJC_PR_readonly) == OBJC_PR_readonly)
+	{
+		flags[i++] = ',';
+		flags[i++] = 'R';
+	}
+	if ((property->attributes & OBJC_PR_copy) == OBJC_PR_copy)
+	{
+		flags[i++] = ',';
+		flags[i++] = 'C';
+	}
+	if ((property->attributes & OBJC_PR_retain) == OBJC_PR_retain)
+	{
+		flags[i++] = ',';
+		flags[i++] = '&';
+	}
+	if ((property->attributes & OBJC_PR_nonatomic) == OBJC_PR_nonatomic)
+	{
+		flags[i++] = ',';
+		flags[i++] = 'N';
+	}
+	encodingSize += i;
+	flags[i] = '\0';
+	size_t setterLength = 0;
+	size_t getterLength = 0;
+	if ((property->attributes & OBJC_PR_getter) == OBJC_PR_getter)
+	{
+		getterLength = strlen(property->getter_name);
+		encodingSize += 2 + getterLength;
+	}
+	if ((property->attributes & OBJC_PR_setter) == OBJC_PR_setter)
+	{
+		setterLength = strlen(property->setter_name);
+		encodingSize += 2 + setterLength;
+	}
+	unsigned char *encoding = malloc(encodingSize);
+	// Set the leading 0 and the offset of the name
+	unsigned char *insert = encoding;
+	*(insert++) = 0;
+	*(insert++) = 0;
+	// Set the type encoding
+	*(insert++) = 'T';
+	memcpy(insert, typeEncoding, typeSize);
+	insert += typeSize;
+	// Set the flags
+	memcpy(insert, flags, i);
+	insert += i;
+	if ((property->attributes & OBJC_PR_getter) == OBJC_PR_getter)
+	{
+		*(insert++) = ',';
+		*(insert++) = 'G';
+		memcpy(insert, property->getter_name, getterLength);
+		insert += getterLength;
+	}
+	if ((property->attributes & OBJC_PR_setter) == OBJC_PR_setter)
+	{
+		*(insert++) = ',';
+		*(insert++) = 'S';
+		memcpy(insert, property->setter_name, setterLength);
+		insert += setterLength;
+	}
+	*(insert++) = ',';
+	*(insert++) = 'V';
+	encoding[1] = (unsigned char)(uintptr_t)(insert - encoding);
+	memcpy(insert, property->name, nameSize);
+	insert += nameSize;
+	*insert = '\0';
+	// If another thread installed the encoding string while we were computing
+	// it, then discard the one that we created and return theirs.
+	if (!__sync_bool_compare_and_swap(&(property->name), name, (char*)encoding))
+	{
+		free(encoding);
+		return property->name + 2;
+	}
+	return (const char*)(encoding + 2);
+}
+
+objc_property_attribute_t *property_copyAttributeList(objc_property_t property,
+                                                      unsigned int *outCount)
+{
+	if (NULL == property) { return NULL; }
+	objc_property_attribute_t attrs[10];
+	int count = 0;
+
+	attrs[count].name = "T";
+	attrs[count].value = property_getTypeEncoding(property);
+	count++;
+	if ((property->attributes & OBJC_PR_copy) == OBJC_PR_copy)
+	{
+		attrs[count].name = "C";
+		attrs[count].value = "";
+		count++;
+	}
+	if ((property->attributes & OBJC_PR_retain) == OBJC_PR_retain)
+	{
+		attrs[count].name = "&";
+		attrs[count].value = "";
+		count++;
+	}
+	if ((property->attributes & OBJC_PR_nonatomic) == OBJC_PR_nonatomic)
+	{
+		attrs[count].name = "N";
+		attrs[count].value = "";
+		count++;
+	}
+	if ((property->attributes & OBJC_PR_getter) == OBJC_PR_getter)
+	{
+		attrs[count].name = "G";
+		attrs[count].value = property->getter_name;
+		count++;
+	}
+	if ((property->attributes & OBJC_PR_setter) == OBJC_PR_setter)
+	{
+		attrs[count].name = "S";
+		attrs[count].value = property->setter_name;
+		count++;
+	}
+	attrs[count].name = "V";
+	attrs[count].value = property_getName(property);
+	count++;
+
+	objc_property_attribute_t *propAttrs = calloc(sizeof(objc_property_attribute_t), count);
+	memcpy(propAttrs, attrs, count * sizeof(objc_property_attribute_t));
+	if (NULL != outCount)
+	{
+		*outCount = count;
+	}
+	return propAttrs;
+}
+
+PRIVATE struct objc_property propertyFromAttrs(const objc_property_attribute_t *attributes,
+                                               unsigned int attributeCount)
+{
+	struct objc_property p = { 0 };
+	for (unsigned int i=0 ; i<attributeCount ; i++)
+	{
+		switch (attributes[i].name[0])
+		{
+			case 'T':
+			{
+				size_t typeSize = strlen(attributes[i].value);
+				char *buffer = malloc(typeSize + 2);
+				buffer[0] = 0;
+				memcpy(buffer+1, attributes[i].value, typeSize);
+				buffer[typeSize+1] = 0;
+				p.getter_types = buffer;
+				break;
+			}
+			case 'S':
+			{
+				p.setter_name = strdup(attributes[i].value);
+				break;
+			}
+			case 'G':
+			{
+				p.getter_name = strdup(attributes[i].value);
+				break;
+			}
+			case 'V':
+			{
+				p.name = strdup(attributes[i].value);
+				break;
+			}
+			case 'C':
+			{
+				p.attributes |= OBJC_PR_copy;
+			}
+			case '&':
+			{
+				p.attributes |= OBJC_PR_retain;
+			}
+			case 'N':
+			{
+				p.attributes |= OBJC_PR_nonatomic;
+			}
+		}
+	}
+	return p;
+}
+
+BOOL class_addProperty(Class cls,
+                       const char *name,
+                       const objc_property_attribute_t *attributes, 
+                       unsigned int attributeCount)
+{
+	if ((Nil == cls) || (NULL == name) || (class_getProperty(cls, name) != 0)) { return NO; }
+	struct objc_property p = propertyFromAttrs(attributes, attributeCount);
+	// If there is a name mismatch, the attributes are invalid.
+	if ((p.name != 0) && (strcmp(name, p.name) != 0)) { return NO; }
+
+	struct objc_property_list *l = calloc(1, sizeof(struct objc_property_list)
+			+ sizeof(struct objc_property));
+	l->count = 0;
+	memcpy(&l->properties, &p, sizeof(struct objc_property));
+	LOCK_RUNTIME_FOR_SCOPE();
+	l->next = cls->properties;
+	cls->properties = l;
+	return YES;
+}
+
+void class_replaceProperty(Class cls,
+                           const char *name,
+                           const objc_property_attribute_t *attributes,
+                           unsigned int attributeCount)
+{
+	if ((Nil == cls) || (NULL == name)) { return; }
+	objc_property_t old = class_getProperty(cls, name);
+	if (NULL == old)
+	{
+		class_addProperty(cls, name, attributes, attributeCount);
+		return;
+	}
+	struct objc_property p = propertyFromAttrs(attributes, attributeCount);
+	memcpy(old, &p, sizeof(struct objc_property));
+	if (NULL == old->name)
+	{
+		old->name = name;
+	}
+}
+char *property_copyAttributeValue(objc_property_t property,
+                                  const char *attributeName)
+{
+	if ((NULL == property) || (NULL == attributeName)) { return NULL; }
+	switch (attributeName[0])
+	{
+		case 'T':
+		{
+			return strdup(property_getTypeEncoding(property));
+		}
+		case 'V':
+		{
+			return strdup(property_getName(property));
+		}
+		case 'S':
+		{
+			return strdup(property->setter_name);
+		}
+		case 'G':
+		{
+			return strdup(property->getter_name);
+		}
+		case 'C':
+		{
+			return ((property->attributes |= OBJC_PR_copy) == OBJC_PR_copy) ? strdup("") : 0;
+		}
+		case '&':
+		{
+			return ((property->attributes |= OBJC_PR_retain) == OBJC_PR_retain) ? strdup("") : 0;
+		}
+		case 'N':
+		{
+			return ((property->attributes |= OBJC_PR_nonatomic) == OBJC_PR_nonatomic) ? strdup("") : 0;
+		}
+	}
+	return 0;
+}
diff --git a/third_party/libobjc/protocol.c b/third_party/libobjc/protocol.c
new file mode 100644
index 0000000000000000000000000000000000000000..e9b80ce93cf2fe7e3714d405738615c3833a42d8
--- /dev/null
+++ b/third_party/libobjc/protocol.c
@@ -0,0 +1,616 @@
+#include "objc/runtime.h"
+#include "protocol.h"
+#include "properties.h"
+#include "class.h"
+#include "lock.h"
+#include <stdlib.h>
+
+#define BUFFER_TYPE struct objc_protocol_list
+#include "buffer.h"
+
+// Get the functions for string hashing
+#include "string_hash.h"
+
+static int protocol_compare(const char *name, 
+                            const struct objc_protocol2 *protocol)
+{
+	return string_compare(name, protocol->name);
+}
+static int protocol_hash(const struct objc_protocol2 *protocol)
+{
+	return string_hash(protocol->name);
+}
+#define MAP_TABLE_NAME protocol
+#define MAP_TABLE_COMPARE_FUNCTION protocol_compare
+#define MAP_TABLE_HASH_KEY string_hash
+#define MAP_TABLE_HASH_VALUE protocol_hash
+#include "hash_table.h"
+
+static protocol_table *known_protocol_table;
+
+void init_protocol_table(void)
+{
+	protocol_initialize(&known_protocol_table, 128);
+}  
+
+static void protocol_table_insert(const struct objc_protocol2 *protocol)
+{
+	protocol_insert(known_protocol_table, (void*)protocol);
+}
+
+struct objc_protocol2 *protocol_for_name(const char *name)
+{
+	return protocol_table_get(known_protocol_table, name);
+}
+
+static id ObjC2ProtocolClass = 0;
+
+static int isEmptyProtocol(struct objc_protocol2 *aProto)
+{
+	int isEmpty = 
+		((aProto->instance_methods == NULL) || 
+			(aProto->instance_methods->count == 0)) &&
+		((aProto->class_methods == NULL) || 
+			(aProto->class_methods->count == 0)) &&
+		((aProto->protocol_list == NULL) ||
+		  (aProto->protocol_list->count == 0));
+	if (aProto->isa == ObjC2ProtocolClass)
+	{
+		struct objc_protocol2 *p2 = (struct objc_protocol2*)aProto;
+		isEmpty &= (p2->optional_instance_methods->count == 0);
+		isEmpty &= (p2->optional_class_methods->count == 0);
+		isEmpty &= (p2->properties == 0) || (p2->properties->count == 0);
+		isEmpty &= (p2->optional_properties == 0) || (p2->optional_properties->count == 0);
+	}
+	return isEmpty;
+}
+
+// FIXME: Make p1 adopt all of the stuff in p2
+static void makeProtocolEqualToProtocol(struct objc_protocol2 *p1,
+                                        struct objc_protocol2 *p2) 
+{
+#define COPY(x) p1->x = p2->x
+	COPY(instance_methods);
+	COPY(class_methods);
+	COPY(protocol_list);
+	if (p1->isa == ObjC2ProtocolClass &&
+		p2->isa == ObjC2ProtocolClass)
+	{
+		COPY(optional_instance_methods);
+		COPY(optional_class_methods);
+		COPY(properties);
+		COPY(optional_properties);
+	}
+#undef COPY
+}
+
+static struct objc_protocol2 *unique_protocol(struct objc_protocol2 *aProto)
+{
+	if (ObjC2ProtocolClass == 0)
+	{
+		ObjC2ProtocolClass = objc_getClass("Protocol2");
+	}
+	struct objc_protocol2 *oldProtocol = 
+		protocol_for_name(aProto->name);
+	if (NULL == oldProtocol)
+	{
+		// This is the first time we've seen this protocol, so add it to the
+		// hash table and ignore it.
+		protocol_table_insert(aProto);
+		return aProto;
+	}
+	if (isEmptyProtocol(oldProtocol))
+	{
+		if (isEmptyProtocol(aProto))
+		{
+			return aProto;
+			// Add protocol to a list somehow.
+		}
+		else
+		{
+			// This protocol is not empty, so we use its definitions
+			makeProtocolEqualToProtocol(oldProtocol, aProto);
+			return aProto;
+		}
+	}
+	else
+	{
+		if (isEmptyProtocol(aProto))
+		{
+			makeProtocolEqualToProtocol(aProto, oldProtocol);
+			return oldProtocol;
+		}
+		else
+		{
+			return oldProtocol;
+			//FIXME: We should really perform a check here to make sure the
+			//protocols are actually the same.
+		}
+	}
+}
+
+static id protocol_class;
+static id protocol_class2;
+enum protocol_version
+{
+	/**
+	 * Legacy (GCC-compatible) protocol version.
+	 */
+	protocol_version_legacy = 2,
+	/**
+	 * New (Objective-C 2-compatible) protocol version.
+	 */
+	protocol_version_objc2 = 3
+};
+
+static BOOL init_protocols(struct objc_protocol_list *protocols)
+{
+	// Protocol2 is a subclass of Protocol, so if we have loaded Protocol2 we
+	// must have also loaded Protocol.
+	if (nil == protocol_class2)
+	{
+		protocol_class = objc_getClass("Protocol");
+		protocol_class2 = objc_getClass("Protocol2");
+	}
+	if (nil == protocol_class2 || nil == protocol_class)
+	{
+		return NO;
+	}
+
+	for (unsigned i=0 ; i<protocols->count ; i++)
+	{
+		struct objc_protocol2 *aProto = protocols->list[i];
+		// Don't initialise a protocol twice
+		if (aProto->isa == protocol_class ||
+			aProto->isa == protocol_class2) { continue ;}
+
+		// Protocols in the protocol list have their class pointers set to the
+		// version of the protocol class that they expect.
+		enum protocol_version version = 
+			(enum protocol_version)(uintptr_t)aProto->isa;
+		switch (version)
+		{
+			default:
+				fprintf(stderr, "Unknown protocol version");
+				abort();
+			case protocol_version_legacy:
+				aProto->isa = protocol_class;
+				break;
+			case protocol_version_objc2:
+				aProto->isa = protocol_class2;
+				break;
+		}
+		// Initialize all of the protocols that this protocol refers to
+		if (NULL != aProto->protocol_list)
+		{
+			init_protocols(aProto->protocol_list);
+		}
+		// Replace this protocol with a unique version of it.
+		protocols->list[i] = unique_protocol(aProto);
+	}
+	return YES;
+}
+
+PRIVATE void objc_init_protocols(struct objc_protocol_list *protocols)
+{
+	if (!init_protocols(protocols))
+	{
+		set_buffered_object_at_index(protocols, buffered_objects++);
+		return;
+	}
+	if (buffered_objects > 0) { return; }
+
+	// If we can load one protocol, then we can load all of them.
+	for (unsigned i=0 ; i<buffered_objects ; i++)
+	{
+		struct objc_protocol_list *c = buffered_object_at_index(i);
+		if (NULL != c)
+		{
+			init_protocols(c);
+			set_buffered_object_at_index(NULL, i);
+		}
+	}
+	compact_buffer();
+}
+
+// Public functions:
+Protocol *objc_getProtocol(const char *name)
+{
+	if (NULL == name) { return NULL; }
+	return (Protocol*)protocol_for_name(name);
+}
+
+BOOL protocol_conformsToProtocol(Protocol *p1, Protocol *p2)
+{
+	if (NULL == p1 || NULL == p2) { return NO; }
+
+	// A protocol trivially conforms to itself
+	if (strcmp(p1->name, p2->name) == 0) { return YES; }
+
+	for (struct objc_protocol_list *list = p1->protocol_list ;
+		list != NULL ; list = list->next)
+	{
+		for (int i=0 ; i<list->count ; i++)
+		{
+			if (strcmp(list->list[i]->name, p2->name) == 0)
+			{
+				return YES;
+			}
+			if (protocol_conformsToProtocol((Protocol*)list->list[i], p2))
+			{
+				return YES;
+			}
+		}
+	}
+	return NO;
+}
+
+BOOL class_conformsToProtocol(Class cls, Protocol *protocol)
+{
+	if (Nil == cls || NULL == protocol) { return NO; }
+	for ( ; Nil != cls ; cls = class_getSuperclass(cls))
+	{
+		for (struct objc_protocol_list *protocols = cls->protocols;
+			protocols != NULL ; protocols = protocols->next)
+		{
+			for (int i=0 ; i<protocols->count ; i++)
+			{
+				Protocol *p1 = (Protocol*)protocols->list[i];
+				if (protocol_conformsToProtocol(p1, protocol))
+				{
+					return YES;
+				}
+			}
+		}
+	}
+	return NO;
+}
+
+static struct objc_method_description_list *
+get_method_list(Protocol *p,
+                BOOL isRequiredMethod,
+                BOOL isInstanceMethod)
+{
+	static id protocol2 = NULL;
+
+	if (NULL == protocol2)
+	{
+		protocol2 = objc_getClass("Protocol2");
+	}
+	struct objc_method_description_list *list;
+	if (isRequiredMethod)
+	{
+		if (isInstanceMethod)
+		{
+			list = p->instance_methods;
+		}
+		else
+		{
+			list = p->class_methods;
+		}
+	}
+	else
+	{
+		if (p->isa != protocol2) { return NULL; }
+
+
+		if (isInstanceMethod)
+		{
+			list = ((Protocol2*)p)->optional_instance_methods;
+		}
+		else
+		{
+			list = ((Protocol2*)p)->optional_class_methods;
+		}
+	}
+	return list;
+}
+
+struct objc_method_description *protocol_copyMethodDescriptionList(Protocol *p,
+	BOOL isRequiredMethod, BOOL isInstanceMethod, unsigned int *count)
+{
+	if (NULL == p) { return NULL; }
+	struct objc_method_description_list *list = 
+		get_method_list(p, isRequiredMethod, isInstanceMethod);
+	*count = 0;
+	if (NULL == list || list->count == 0) { return NULL; }
+
+	*count = list->count;
+	struct objc_method_description *out = 
+		calloc(sizeof(struct objc_method_description_list), list->count);
+
+	for (int i=0 ; i<list->count ; i++)
+	{
+		out[i].name = sel_registerTypedName_np(list->methods[i].name,
+		                                       list->methods[i].types);
+		out[i].types = list->methods[i].types;
+	}
+	return out;
+}
+
+Protocol*__unsafe_unretained* protocol_copyProtocolList(Protocol *p, unsigned int *count)
+{
+	if (NULL == p) { return NULL; }
+	*count = 0;
+	if (p->protocol_list == NULL || p->protocol_list->count ==0)
+	{
+		return NULL;
+	}
+
+	Protocol **out = calloc(sizeof(Protocol*), p->protocol_list->count);
+	for (int i=0 ; i<p->protocol_list->count ; i++)
+	{
+		out[i] = (Protocol*)p->protocol_list->list[i];
+	}
+	return NULL;
+}
+
+objc_property_t *protocol_copyPropertyList(Protocol *protocol,
+                                           unsigned int *outCount)
+{
+	if (NULL == protocol) { return NULL; }
+	if (protocol->isa != ObjC2ProtocolClass)
+	{
+		return NULL;
+	}
+	Protocol2 *p = (Protocol2*)protocol;
+	struct objc_property_list *properties = p->properties;
+	unsigned int count = 0;
+	if (NULL != properties)
+	{
+		count = properties->count;
+	}
+	if (NULL != p->optional_properties)
+	{
+		count = p->optional_properties->count;
+	}
+	if (0 == count)
+	{
+		return NULL;
+	}
+	objc_property_t *list = calloc(sizeof(objc_property_t), count);
+	unsigned int out = 0;
+	if (properties)
+	{
+		for (int i=0 ; i<properties->count ; i++)
+		{
+			list[out] = &properties->properties[i];
+		}
+	}
+	properties = p->optional_properties;
+	if (properties)
+	{
+		for (int i=0 ; i<properties->count ; i++)
+		{
+			list[out] = &properties->properties[i];
+		}
+	}
+	*outCount = count;
+	return list;
+}
+
+objc_property_t protocol_getProperty(Protocol *protocol,
+                                     const char *name,
+                                     BOOL isRequiredProperty,
+                                     BOOL isInstanceProperty)
+{
+	if (NULL == protocol) { return NULL; }
+	// Class properties are not supported yet (there is no language syntax for
+	// defining them!)
+	if (!isInstanceProperty) { return NULL; }
+	if (protocol->isa != ObjC2ProtocolClass)
+	{
+		return NULL;
+	}
+	Protocol2 *p = (Protocol2*)protocol;
+	struct objc_property_list *properties = 
+	    isRequiredProperty ? p->properties : p->optional_properties;
+	while (NULL != properties)
+	{
+		for (int i=0 ; i<properties->count ; i++)
+		{
+			objc_property_t prop = &properties->properties[i];
+			if (strcmp(prop->name, name) == 0)
+			{
+				return prop;
+			}
+		}
+		properties = properties->next;
+	}
+	return NULL;
+}
+
+
+struct objc_method_description 
+protocol_getMethodDescription(Protocol *p,
+                              SEL aSel,
+                              BOOL isRequiredMethod,
+                              BOOL isInstanceMethod)
+{
+	struct objc_method_description d = {0,0};
+	struct objc_method_description_list *list = 
+		get_method_list(p, isRequiredMethod, isInstanceMethod);
+	if (NULL == list)
+	{
+		return d;
+	}
+	// TODO: We could make this much more efficient if 
+	for (int i=0 ; i<list->count ; i++)
+	{
+		SEL s = sel_registerTypedName_np(list->methods[i].name, 0);
+		if (sel_isEqual(s, aSel))
+		{
+			d.name = s;
+			d.types = list->methods[i].types;
+			break;
+		}
+	}
+	return d;
+}
+
+
+const char *protocol_getName(Protocol *p)
+{
+	if (NULL != p)
+	{
+		return p->name;
+	}
+	return NULL;
+}
+
+BOOL protocol_isEqual(Protocol *p, Protocol *other)
+{
+	if (NULL == p || NULL == other)
+	{
+		return NO;
+	}
+	if (p == other || 
+		p->name == other->name ||
+		0 == strcmp(p->name, other->name))
+	{
+		return YES;
+	}
+	return NO;
+}
+
+Protocol*__unsafe_unretained* objc_copyProtocolList(unsigned int *outCount)
+{
+	unsigned int total = known_protocol_table->table_used;
+	Protocol **p = calloc(sizeof(Protocol*), known_protocol_table->table_used);
+
+	struct protocol_table_enumerator *e = NULL;
+	Protocol *next;
+
+	unsigned int count = 0;
+	while ((count < total) && (next = protocol_next(known_protocol_table, &e)))
+	{
+		p[count++] = next;
+	}
+	if (NULL != outCount)
+	{
+		*outCount = total;
+	}
+	return p;
+}
+
+
+Protocol *objc_allocateProtocol(const char *name)
+{
+	if (objc_getProtocol(name) != NULL) { return NULL; }
+	Protocol *p = calloc(1, sizeof(Protocol2));
+	p->name = strdup(name);
+	return p;
+}
+void objc_registerProtocol(Protocol *proto)
+{
+	if (NULL == proto) { return; }
+	LOCK_RUNTIME_FOR_SCOPE();
+	if (objc_getProtocol(proto->name) != NULL) { return; }
+	if (nil != proto->isa) { return; }
+	proto->isa = ObjC2ProtocolClass;
+	protocol_table_insert((struct objc_protocol2*)proto);
+}
+void protocol_addMethodDescription(Protocol *aProtocol,
+                                   SEL name,
+                                   const char *types,
+                                   BOOL isRequiredMethod,
+                                   BOOL isInstanceMethod)
+{
+	if ((NULL == aProtocol) || (NULL == name) || (NULL == types)) { return; }
+	if (nil != aProtocol->isa) { return; }
+	Protocol2 *proto = (Protocol2*)aProtocol;
+	struct objc_method_description_list **listPtr;
+	if (isInstanceMethod)
+	{
+		if (isRequiredMethod)
+		{
+			listPtr = &proto->instance_methods;
+		}
+		else
+		{
+			listPtr = &proto->optional_instance_methods;
+		}
+	}
+	else
+	{
+		if (isRequiredMethod)
+		{
+			listPtr = &proto->class_methods;
+		}
+		else
+		{
+			listPtr = &proto->optional_class_methods;
+		}
+	}
+	if (NULL == *listPtr)
+	{
+		*listPtr = calloc(1, sizeof(struct objc_method_description_list) + sizeof(struct objc_method_description));
+		(*listPtr)->count = 1;
+	}
+	else
+	{
+		(*listPtr)->count++;
+		*listPtr = realloc(*listPtr, sizeof(struct objc_method_description_list) +
+				sizeof(struct objc_method_description) * (*listPtr)->count);
+	}
+	struct objc_method_description_list *list = *listPtr;
+	int index = list->count-1;
+	list->methods[index].name = sel_getName(name);
+	list->methods[index].types= types;
+}
+void protocol_addProtocol(Protocol *aProtocol, Protocol *addition)
+{
+	if ((NULL == aProtocol) || (NULL == addition)) { return; }
+	Protocol2 *proto = (Protocol2*)aProtocol;
+	if (NULL == proto->protocol_list)
+	{
+		proto->protocol_list = calloc(1, sizeof(struct objc_property_list) + sizeof(Protocol2*));
+		proto->protocol_list->count = 1;
+	}
+	else
+	{
+		proto->protocol_list->count++;
+		proto->protocol_list = realloc(proto->protocol_list, sizeof(struct objc_property_list) +
+				proto->protocol_list->count * sizeof(Protocol2*));
+		proto->protocol_list->count = 1;
+	}
+	proto->protocol_list->list[proto->protocol_list->count-1] = (Protocol2*)addition;
+}
+void protocol_addProperty(Protocol *aProtocol,
+                          const char *name,
+                          const objc_property_attribute_t *attributes,
+                          unsigned int attributeCount,
+                          BOOL isRequiredProperty,
+                          BOOL isInstanceProperty)
+{
+	if ((NULL == aProtocol) || (NULL == name)) { return; }
+	if (nil != aProtocol->isa) { return; }
+	if (!isInstanceProperty) { return; }
+	Protocol2 *proto = (Protocol2*)aProtocol;
+	struct objc_property_list **listPtr;
+	if (isRequiredProperty)
+	{
+		listPtr = &proto->properties;
+	}
+	else
+	{
+		listPtr = &proto->optional_properties;
+	}
+	if (NULL == *listPtr)
+	{
+		*listPtr = calloc(1, sizeof(struct objc_property_list) + sizeof(struct objc_property));
+		(*listPtr)->count = 1;
+	}
+	else
+	{
+		(*listPtr)->count++;
+		*listPtr = realloc(*listPtr, sizeof(struct objc_property_list) +
+				sizeof(struct objc_property) * (*listPtr)->count);
+	}
+	struct objc_property_list *list = *listPtr;
+	int index = list->count-1;
+	struct objc_property p = propertyFromAttrs(attributes, attributeCount);
+	p.name = strdup(name);
+	memcpy(&(list->properties[index]), &p, sizeof(p));
+}
+
diff --git a/third_party/libobjc/protocol.h b/third_party/libobjc/protocol.h
new file mode 100644
index 0000000000000000000000000000000000000000..d44cd3c4468deb3de5284783e83cd3829458b82f
--- /dev/null
+++ b/third_party/libobjc/protocol.h
@@ -0,0 +1,121 @@
+#include "selector.h"
+#include <stdlib.h>
+
+struct objc_method_description_list
+{
+	/** 
+	 * Number of method descriptions in this list.
+	 */
+	int count;
+	/**
+	 * Methods in this list.  Note: these selectors are NOT resolved.  The name
+	 * field points to the name, not to the index of the uniqued version of the
+	 * name.  You must not use them for dispatch.
+	 */
+	struct objc_selector methods[];
+};
+
+
+#ifdef __OBJC__
+@interface Object { id isa; } @end
+/**
+ * Definition of the Protocol type.  Protocols are objects, but are rarely used
+ * as such.
+ */
+@interface Protocol : Object
+{
+	@public
+#else
+struct objc_protocol
+{
+	/** Class pointer. */
+	id                                   isa;
+#endif 
+	/** 
+	 * The name of this protocol.  Two protocols are regarded as identical if
+	 * they have the same name. 
+	 */
+	char                                *name;
+	/**
+	 * The list of protocols that this protocol conforms to.
+	 */
+	struct objc_protocol_list           *protocol_list;
+	/**
+	 * List of instance methods required by this protocol.
+	 */
+	struct objc_method_description_list *instance_methods;
+	/**
+	 * List of class methods required by this protocol.
+	 */
+	struct objc_method_description_list *class_methods; 
+}
+#ifdef __OBJC__
+@end
+#else
+;
+#endif 
+
+#ifdef __OBJC__
+@interface Protocol2 : Protocol
+{
+	@public
+#else
+typedef struct objc_protocol2
+{
+	/**
+	 * Redefinition of the superclass ivars in the C version.
+	 */
+	id                                   isa;
+	char                                *name;
+	struct objc_protocol_list           *protocol_list;
+	struct objc_method_description_list *instance_methods;
+	struct objc_method_description_list *class_methods; 
+#endif 
+	/**
+	 * Instance methods that are declared as optional for this protocol.
+	 */
+	struct objc_method_description_list *optional_instance_methods;
+	/**
+	 * Class methods that are declared as optional for this protocol.
+	 */
+	struct objc_method_description_list *optional_class_methods; 
+	/**
+	 * Properties that are required by this protocol.
+	 */
+	struct objc_property_list           *properties;
+	/**
+	 * Optional properties. 
+	 */
+	struct objc_property_list           *optional_properties;
+}
+#ifdef __OBJC__
+@end
+#else
+Protocol2;
+#endif
+
+/**
+ * List of protocols.  Attached to a class or a category by the compiler and to
+ * a class by the runtime.
+ */
+struct objc_protocol_list
+{
+	/**
+	 * Additional protocol lists.  Loading a category that declares protocols
+	 * will cause a new list to be prepended using this pointer to the protocol
+	 * list for the class.  Unlike methods, protocols can not be overridden,
+	 * although it is possible for a protocol to appear twice.
+	 */
+	struct objc_protocol_list *next;
+	/**
+	 * The number of protocols in this list.
+	 */
+	size_t                     count;
+	/**
+	 * An array of protocols.  Actually contains count elements, not 1.
+	 *
+	 * The instances in this array may be any version of protocols.
+	 */
+	Protocol2                 *list[];
+};
+
diff --git a/third_party/libobjc/runtime.c b/third_party/libobjc/runtime.c
new file mode 100644
index 0000000000000000000000000000000000000000..627be9a237c3d24839ca2f121a8352212e4161ab
--- /dev/null
+++ b/third_party/libobjc/runtime.c
@@ -0,0 +1,786 @@
+#include "objc/runtime.h"
+#include "selector.h"
+#include "class.h"
+#include "protocol.h"
+#include "ivar.h"
+#include "method_list.h"
+#include "lock.h"
+#include "dtable.h"
+#include "gc_ops.h"
+
+/* Make glibc export strdup() */
+
+#if defined __GLIBC__
+	#define __USE_BSD 1
+#endif
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+struct objc_slot *objc_get_slot(Class cls, SEL selector);
+#define CHECK_ARG(arg) if (0 == arg) { return 0; }
+
+/**
+ * Calls C++ destructors in the correct order.
+ */
+PRIVATE void call_cxx_destruct(id obj)
+{
+	static SEL cxx_destruct;
+	if (NULL == cxx_destruct)
+	{
+		cxx_destruct = sel_registerName(".cxx_destruct");
+	}
+	// Don't call object_getClass(), because we want to get hidden classes too
+	Class cls = classForObject(obj);
+
+	while (cls)
+	{
+		struct objc_slot *slot = objc_get_slot(cls, cxx_destruct);
+		cls = Nil;
+		if (NULL != slot)
+		{
+			cls = slot->owner->super_class;
+			slot->method(obj, cxx_destruct);
+		}
+	}
+}
+
+static void call_cxx_construct_for_class(Class cls, id obj)
+{
+	static SEL cxx_construct;
+	if (NULL == cxx_construct)
+	{
+		cxx_construct = sel_registerName(".cxx_contruct");
+	}
+	struct objc_slot *slot = objc_get_slot(cls, cxx_construct);
+	if (NULL != slot)
+	{
+		cls = slot->owner->super_class;
+		if (Nil != cls)
+		{
+			call_cxx_construct_for_class(cls, obj);
+		}
+		slot->method(obj, cxx_construct);
+	}
+}
+
+PRIVATE void call_cxx_construct(id obj)
+{
+	call_cxx_construct_for_class(classForObject(obj), obj);
+}
+
+/**
+ * Looks up the instance method in a specific class, without recursing into
+ * superclasses.
+ */
+static Method class_getInstanceMethodNonrecursive(Class aClass, SEL aSelector)
+{
+	for (struct objc_method_list *methods = aClass->methods;
+		methods != NULL ; methods = methods->next)
+	{
+		for (int i=0 ; i<methods->count ; i++)
+		{
+			Method method = &methods->methods[i];
+			if (sel_isEqual(method->selector, aSelector))
+			{
+				return method;
+			}
+		}
+	}
+	return NULL;
+}
+
+static void objc_updateDtableForClassContainingMethod(Method m)
+{
+	Class nextClass = Nil;
+	void *state = NULL;
+	SEL sel = method_getName(m);
+	while (Nil != (nextClass = objc_next_class(&state)))
+	{
+		if (class_getInstanceMethodNonrecursive(nextClass, sel) == m)
+		{
+			objc_update_dtable_for_class(nextClass);
+			return;
+		}
+	}
+}
+
+BOOL class_addIvar(Class cls, const char *name, size_t size, uint8_t alignment,
+		const char *types)
+{
+	CHECK_ARG(cls);
+	CHECK_ARG(name);
+	CHECK_ARG(types);
+	// You can't add ivars to initialized classes.  Note: We can't use the
+	// resolved flag here because class_getInstanceVariable() sets it.
+	if (objc_test_class_flag(cls, objc_class_flag_initialized))
+	{
+		return NO;
+	}
+
+	if (class_getInstanceVariable(cls, name) != NULL)
+	{
+		return NO;
+	}
+
+	struct objc_ivar_list *ivarlist = cls->ivars;
+
+	if (NULL == ivarlist)
+	{
+		cls->ivars = malloc(sizeof(struct objc_ivar_list) + sizeof(struct objc_ivar));
+		cls->ivars->count = 1;
+	}
+	else
+	{
+		ivarlist->count++;
+		// objc_ivar_list contains one ivar.  Others follow it.
+		cls->ivars = realloc(ivarlist, sizeof(struct objc_ivar_list) +
+				(ivarlist->count) * sizeof(struct objc_ivar));
+	}
+	Ivar ivar = &cls->ivars->ivar_list[cls->ivars->count - 1];
+	ivar->name = strdup(name);
+	ivar->type = strdup(types);
+	// Round up the offset of the ivar so it is correctly aligned.
+	long offset = cls->instance_size >> alignment;
+
+	if (offset << alignment != cls->instance_size)
+	{
+		offset++;
+	}
+	offset <<= alignment;
+
+	ivar->offset = offset;
+	// Increase the instance size to make space for this.
+	cls->instance_size = ivar->offset + size;
+	return YES;
+}
+
+BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
+{
+	CHECK_ARG(cls);
+	CHECK_ARG(name);
+	CHECK_ARG(imp);
+	CHECK_ARG(types);
+	const char *methodName = sel_getName(name);
+	struct objc_method_list *methods;
+	for (methods=cls->methods; methods!=NULL ; methods=methods->next)
+	{
+		for (int i=0 ; i<methods->count ; i++)
+		{
+			Method method = &methods->methods[i];
+			if (strcmp(sel_getName(method->selector), methodName) == 0)
+			{
+				return NO;
+			}
+		}
+	}
+
+	methods = malloc(sizeof(struct objc_method_list) + sizeof(struct objc_method));
+	methods->next = cls->methods;
+	cls->methods = methods;
+
+	methods->count = 1;
+	methods->methods[0].selector = sel_registerTypedName_np(methodName, types);
+	methods->methods[0].types = strdup(types);
+	methods->methods[0].imp = imp;
+
+	if (objc_test_class_flag(cls, objc_class_flag_resolved))
+	{
+		add_method_list_to_class(cls, methods);
+	}
+
+	return YES;
+}
+
+BOOL class_addProtocol(Class cls, Protocol *protocol)
+{
+	CHECK_ARG(cls);
+	CHECK_ARG(protocol);
+	if (class_conformsToProtocol(cls, protocol)) { return NO; }
+	struct objc_protocol_list *protocols =
+		malloc(sizeof(struct objc_protocol_list) + sizeof(Protocol2*));
+	if (protocols == NULL) { return NO; }
+	protocols->next = cls->protocols;
+	protocols->count = 1;
+	protocols->list[0] = (Protocol2*)protocol;
+	cls->protocols = protocols;
+
+	return YES;
+}
+
+Ivar * class_copyIvarList(Class cls, unsigned int *outCount)
+{
+	CHECK_ARG(cls);
+	struct objc_ivar_list *ivarlist = NULL;
+	unsigned int count = 0;
+	unsigned int index;
+	Ivar *list;
+
+	if (Nil != cls)
+	{
+		ivarlist = cls->ivars;
+	}
+	if (ivarlist != NULL)
+	{
+		count = ivarlist->count;
+	}
+	if (outCount != NULL)
+	{
+		*outCount = count;
+	}
+	if (count == 0)
+	{
+		return NULL;
+	}
+
+	list = malloc((count + 1) * sizeof(struct objc_ivar *));
+	list[count] = NULL;
+	count = 0;
+	for (index = 0; index < ivarlist->count; index++)
+	{
+		list[count++] = &ivarlist->ivar_list[index];
+	}
+
+	return list;
+}
+
+Method * class_copyMethodList(Class cls, unsigned int *outCount)
+{
+	CHECK_ARG(cls);
+	unsigned int count = 0;
+	Method *list;
+	struct objc_method_list *methods;
+
+	if (cls != NULL)
+	{
+		for (methods = cls->methods; methods != NULL; methods = methods->next)
+		{
+			count += methods->count;
+		}
+	}
+	if (outCount != NULL)
+	{
+		*outCount = count;
+	}
+	if (count == 0)
+	{
+		return NULL;
+	}
+
+	list = malloc((count + 1) * sizeof(struct objc_method *));
+	list[count] = NULL;
+	count = 0;
+	for (methods = cls->methods; methods != NULL; methods = methods->next)
+	{
+		unsigned int	index;
+		for (index = 0; index < methods->count; index++)
+		{
+			list[count++] = &methods->methods[index];
+		}
+	}
+
+	return list;
+}
+
+Protocol*__unsafe_unretained* class_copyProtocolList(Class cls, unsigned int *outCount)
+{
+	CHECK_ARG(cls);
+	struct objc_protocol_list *protocolList = NULL;
+	struct objc_protocol_list *list;
+	unsigned int count = 0;
+	Protocol **protocols;
+
+	if (Nil != cls)
+	{
+		protocolList = cls->protocols;
+	}
+	for (list = protocolList; list != NULL; list = list->next)
+	{
+		count += list->count;
+	}
+	if (outCount != NULL)
+	{
+		*outCount = count;
+	}
+	if (count == 0)
+	{
+		return NULL;
+	}
+
+	protocols = malloc((count + 1) * sizeof(Protocol *));
+	protocols[count] = NULL;
+	count = 0;
+	for (list = protocolList; list != NULL; list = list->next)
+	{
+		memcpy(&protocols[count], list->list, list->count * sizeof(Protocol *));
+		count += list->count;
+	}
+	return protocols;
+}
+
+id class_createInstance(Class cls, size_t extraBytes)
+{
+	CHECK_ARG(cls);
+	if (sizeof(id) == 4)
+	{
+		if (cls == SmallObjectClasses[0])
+		{
+			return (id)1;
+		}
+	}
+	else
+	{
+		for (int i=0 ; i<4 ; i++)
+		{
+			if (cls == SmallObjectClasses[i])
+			{
+				return (id)(uintptr_t)((i<<1)+1);
+			}
+		}
+	}
+
+	if (Nil == cls)	{ return nil; }
+	id obj = gc->allocate_class(cls, extraBytes);
+	obj->isa = cls;
+	call_cxx_construct(obj);
+	return obj;
+}
+
+id object_copy(id obj, size_t size)
+{
+	Class cls = object_getClass(obj);
+	id cpy = class_createInstance(cls, size - class_getInstanceSize(cls));
+	memcpy(((char*)cpy + sizeof(id)), ((char*)obj + sizeof(id)), size - sizeof(id));
+	return cpy;
+}
+
+id object_dispose(id obj)
+{
+	call_cxx_destruct(obj);
+	gc->free_object(obj);
+	return nil;
+}
+
+Method class_getInstanceMethod(Class aClass, SEL aSelector)
+{
+	CHECK_ARG(aClass);
+	CHECK_ARG(aSelector);
+	// If the class has a dtable installed, then we can use the fast path
+	if (classHasInstalledDtable(aClass))
+	{
+		// Do a dtable lookup to find out which class the method comes from.
+		struct objc_slot *slot = objc_get_slot(aClass, aSelector);
+		if (NULL == slot)
+		{
+			slot = objc_get_slot(aClass, sel_registerName(sel_getName(aSelector)));
+			if (NULL == slot)
+			{
+				return NULL;
+			}
+		}
+
+		// Now find the typed variant of the selector, with the correct types.
+		aSelector = slot->selector;
+
+		// Then do the slow lookup to find the method.
+		return class_getInstanceMethodNonrecursive(slot->owner, aSelector);
+	}
+	Method m = class_getInstanceMethodNonrecursive(aClass, aSelector);
+	if (NULL != m)
+	{
+		return m;
+	}
+	return class_getInstanceMethod(class_getSuperclass(aClass), aSelector);
+}
+
+Method class_getClassMethod(Class aClass, SEL aSelector)
+{
+	return class_getInstanceMethod(object_getClass((id)aClass), aSelector);
+}
+
+Ivar class_getClassVariable(Class cls, const char* name)
+{
+	// Note: We don't have compiler support for cvars in ObjC
+	return class_getInstanceVariable(object_getClass((id)cls), name);
+}
+
+size_t class_getInstanceSize(Class cls)
+{
+	if (Nil == cls) { return 0; }
+	return cls->instance_size;
+}
+
+Ivar class_getInstanceVariable(Class cls, const char *name)
+{
+	if (name != NULL)
+	{
+		while (cls != Nil)
+		{
+			struct objc_ivar_list *ivarlist = cls->ivars;
+
+			if (ivarlist != NULL)
+			{
+				for (int i = 0; i < ivarlist->count; i++)
+				{
+					Ivar ivar = &ivarlist->ivar_list[i];
+					if (strcmp(ivar->name, name) == 0)
+					{
+						return ivar;
+					}
+				}
+			}
+			cls = class_getSuperclass(cls);
+		}
+	}
+	return NULL;
+}
+
+// The format of the char* is undocumented.  This function is only ever used in
+// conjunction with class_setIvarLayout().
+const char *class_getIvarLayout(Class cls)
+{
+	CHECK_ARG(cls);
+	return (char*)cls->ivars;
+}
+
+
+const char * class_getName(Class cls)
+{
+	if (Nil == cls) { return "nil"; }
+	return cls->name;
+}
+
+int class_getVersion(Class theClass)
+{
+	CHECK_ARG(theClass);
+	return theClass->version;
+}
+
+const char *class_getWeakIvarLayout(Class cls)
+{
+	assert(0 && "Weak ivars not supported");
+	return NULL;
+}
+
+BOOL class_isMetaClass(Class cls)
+{
+	CHECK_ARG(cls);
+	return objc_test_class_flag(cls, objc_class_flag_meta);
+}
+
+IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)
+{
+	if (Nil == cls) { return (IMP)0; }
+	SEL sel = sel_registerTypedName_np(sel_getName(name), types);
+	Method method = class_getInstanceMethodNonrecursive(cls, sel);
+	if (method == NULL)
+	{
+		class_addMethod(cls, sel, imp, types);
+		return NULL;
+	}
+	IMP old = (IMP)method->imp;
+	method->imp = imp;
+
+	if (objc_test_class_flag(cls, objc_class_flag_resolved))
+	{
+		objc_update_dtable_for_class(cls);
+	}
+
+	return old;
+}
+
+
+void class_setIvarLayout(Class cls, const char *layout)
+{
+	if ((Nil == cls) || (NULL == layout)) { return; }
+	struct objc_ivar_list *list = (struct objc_ivar_list*)layout;
+	size_t listsize = sizeof(struct objc_ivar_list) +
+			sizeof(struct objc_ivar) * (list->count);
+	cls->ivars = malloc(listsize);
+	memcpy(cls->ivars, list, listsize);
+}
+
+__attribute__((deprecated))
+Class class_setSuperclass(Class cls, Class newSuper)
+{
+	CHECK_ARG(cls);
+	CHECK_ARG(newSuper);
+	if (Nil == cls) { return Nil; }
+	Class oldSuper = cls->super_class;
+	cls->super_class = newSuper;
+	return oldSuper;
+}
+
+void class_setVersion(Class theClass, int version)
+{
+	if (Nil == theClass) { return; }
+	theClass->version = version;
+}
+
+void class_setWeakIvarLayout(Class cls, const char *layout)
+{
+	assert(0 && "Not implemented");
+}
+
+const char * ivar_getName(Ivar ivar)
+{
+	CHECK_ARG(ivar);
+	return ivar->name;
+}
+
+ptrdiff_t ivar_getOffset(Ivar ivar)
+{
+	CHECK_ARG(ivar);
+	return ivar->offset;
+}
+
+const char * ivar_getTypeEncoding(Ivar ivar)
+{
+	CHECK_ARG(ivar);
+	return ivar->type;
+}
+
+
+void method_exchangeImplementations(Method m1, Method m2)
+{
+	if (NULL == m1 || NULL == m2) { return; }
+	IMP tmp = (IMP)m1->imp;
+	m1->imp = m2->imp;
+	m2->imp = tmp;
+	objc_updateDtableForClassContainingMethod(m1);
+	objc_updateDtableForClassContainingMethod(m2);
+}
+
+IMP method_getImplementation(Method method)
+{
+	if (NULL == method) { return (IMP)NULL; }
+	return (IMP)method->imp;
+}
+
+SEL method_getName(Method method)
+{
+	if (NULL == method) { return (SEL)NULL; }
+	return (SEL)method->selector;
+}
+
+
+IMP method_setImplementation(Method method, IMP imp)
+{
+	if (NULL == method) { return (IMP)NULL; }
+	IMP old = (IMP)method->imp;
+	method->imp = old;
+	objc_updateDtableForClassContainingMethod(method);
+	return old;
+}
+
+id objc_getRequiredClass(const char *name)
+{
+	CHECK_ARG(name);
+	id cls = objc_getClass(name);
+	if (nil == cls)
+	{
+		abort();
+	}
+	return cls;
+}
+
+static void freeMethodLists(Class aClass)
+{
+	struct objc_method_list *methods = aClass->methods;
+	while(methods != NULL)
+	{
+		for (int i=0 ; i<methods->count ; i++)
+		{
+			free((void*)methods->methods[i].types);
+		}
+		struct objc_method_list *current = methods;
+	   	methods = methods->next;
+		free(current);
+	}
+}
+
+static void freeIvarLists(Class aClass)
+{
+	struct objc_ivar_list *ivarlist = aClass->ivars;
+	if (NULL == ivarlist) { return; }
+
+	for (int i=0 ; i<ivarlist->count ; i++)
+	{
+		Ivar ivar = &ivarlist->ivar_list[i];
+		free((void*)ivar->type);
+		free((void*)ivar->name);
+	}
+	free(ivarlist);
+}
+
+/*
+ * Removes a class from the subclass list found on its super class.
+ * Must be called with the objc runtime mutex locked.
+ */
+static inline void safe_remove_from_subclass_list(Class cls)
+{
+	// If this class hasn't been added to the class hierarchy, then this is easy
+	if (!objc_test_class_flag(cls, objc_class_flag_resolved)) { return; }
+	Class sub = cls->super_class->subclass_list;
+	if (sub == cls)
+	{
+		cls->super_class->subclass_list = cls->sibling_class;
+	}
+	else
+	{
+		while (sub != NULL)
+		{
+			if (sub->sibling_class == cls)
+			{
+				sub->sibling_class = cls->sibling_class;
+				break;
+			}
+			sub = sub->sibling_class;
+		}
+	}
+}
+
+void objc_disposeClassPair(Class cls)
+{
+	if (0 == cls) { return; }
+	Class meta = ((id)cls)->isa;
+	// Remove from the runtime system so nothing tries updating the dtable
+	// while we are freeing the class.
+	{
+		LOCK_RUNTIME_FOR_SCOPE();
+		safe_remove_from_subclass_list(meta);
+		safe_remove_from_subclass_list(cls);
+	}
+
+	// Free the method and ivar lists.
+	freeMethodLists(cls);
+	freeMethodLists(meta);
+	freeIvarLists(cls);
+	if (cls->dtable != uninstalled_dtable)
+	{
+		free_dtable(cls->dtable);
+	}
+	if (meta->dtable != uninstalled_dtable)
+	{
+		free_dtable(meta->dtable);
+	}
+
+	// Free the class and metaclass
+	gc->free(meta);
+	gc->free(cls);
+}
+
+Class objc_allocateClassPair(Class superclass, const char *name, size_t extraBytes)
+{
+	// Check the class doesn't already exist.
+	if (nil != objc_lookUpClass(name)) { return Nil; }
+
+	Class newClass = gc->malloc(sizeof(struct objc_class) + extraBytes);
+
+	if (Nil == newClass) { return Nil; }
+
+	// Create the metaclass
+	Class metaClass = gc->malloc(sizeof(struct objc_class));
+
+	if (Nil == superclass)
+	{
+		/*
+		 * Metaclasses of root classes are precious little flowers and work a
+		 * little differently:
+		 */
+		metaClass->isa = metaClass;
+		metaClass->super_class = newClass;
+	}
+	else
+	{
+		// Initialize the metaclass
+		// Set the meta-metaclass pointer to the name.  The runtime will fix this
+		// in objc_resolve_class().
+		metaClass->isa = (Class)superclass->isa->isa->name;
+		metaClass->super_class = superclass->isa;
+	}
+	metaClass->name = strdup(name);
+	metaClass->info = objc_class_flag_meta | objc_class_flag_user_created |
+		objc_class_flag_new_abi;
+	metaClass->dtable = uninstalled_dtable;
+	metaClass->instance_size = sizeof(struct objc_class);
+
+	// Set up the new class
+	newClass->isa = metaClass;
+	// Set the superclass pointer to the name.  The runtime will fix this when
+	// the class links are resolved.
+	newClass->super_class = (Nil == superclass) ? Nil : (Class)(superclass->name);
+
+	newClass->name = strdup(name);
+	newClass->info = objc_class_flag_class | objc_class_flag_user_created |
+		objc_class_flag_new_abi;
+	newClass->dtable = uninstalled_dtable;
+
+	if (Nil == superclass)
+	{
+		newClass->instance_size = sizeof(struct objc_class);
+	}
+	else
+	{
+		newClass->instance_size = superclass->instance_size;
+	}
+
+	return newClass;
+}
+
+
+void *object_getIndexedIvars(id obj)
+{
+	CHECK_ARG(obj);
+	size_t size = classForObject(obj)->instance_size;
+	if ((0 == size) && class_isMetaClass(classForObject(obj)))
+	{
+		Class cls = (Class)obj;
+		if (objc_test_class_flag(cls, objc_class_flag_new_abi))
+		{
+			size = sizeof(struct objc_class);
+		}
+		else
+		{
+			size = sizeof(struct legacy_abi_objc_class);
+		}
+	}
+	return ((char*)obj) + size;
+}
+
+Class object_getClass(id obj)
+{
+	CHECK_ARG(obj);
+	Class isa = classForObject(obj);
+	while ((Nil != isa) && objc_test_class_flag(isa, objc_class_flag_hidden_class))
+	{
+		isa = isa->super_class;
+	}
+	return isa;
+}
+
+Class object_setClass(id obj, Class cls)
+{
+	CHECK_ARG(obj);
+	// If this is a small object, then don't set its class.
+	uintptr_t addr = (uintptr_t)obj;
+	if (addr & 1) { return classForObject(obj); }
+	Class oldClass =  obj->isa;
+	obj->isa = cls;
+	return oldClass;
+}
+
+const char *object_getClassName(id obj)
+{
+	CHECK_ARG(obj);
+	return class_getName(object_getClass(obj));
+}
+
+void objc_registerClassPair(Class cls)
+{
+	LOCK_RUNTIME_FOR_SCOPE();
+	class_table_insert(cls);
+}
+
diff --git a/third_party/libobjc/sarray2.c b/third_party/libobjc/sarray2.c
new file mode 100644
index 0000000000000000000000000000000000000000..b9ca967fa6914a186272edc8a2855c8cb21f17f3
--- /dev/null
+++ b/third_party/libobjc/sarray2.c
@@ -0,0 +1,204 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "sarray2.h"
+#include "visibility.h"
+
+static void *EmptyArrayData[256];
+static SparseArray EmptyArray = { 0xff, 0, 0, (void**)&EmptyArrayData};
+
+#define MAX_INDEX(sarray) (sarray->mask >> sarray->shift)
+#define DATA_SIZE(sarray) ((sarray->mask >> sarray->shift) + 1)
+
+// Tweak this value to trade speed for memory usage.  Bigger values use more
+// memory, but give faster lookups.  
+#define base_shift 8
+#define base_mask ((1<<base_shift) - 1)
+
+static void init_pointers(SparseArray * sarray)
+{
+	sarray->data = calloc(DATA_SIZE(sarray), sizeof(void*));
+	if(sarray->shift != 0)
+	{
+		for(unsigned i=0 ; i<=MAX_INDEX(sarray) ; i++)
+		{
+			sarray->data[i] = &EmptyArray;
+		}
+	}
+}
+PRIVATE SparseArray * SparseArrayNewWithDepth(uint32_t depth)
+{
+	SparseArray * sarray = calloc(1, sizeof(SparseArray));
+	sarray->refCount = 1;
+	sarray->shift = depth-base_shift;
+	sarray->mask = base_mask << sarray->shift;
+	init_pointers(sarray);
+	return sarray;
+}
+
+PRIVATE SparseArray *SparseArrayNew()
+{
+	return SparseArrayNewWithDepth(32);
+}
+PRIVATE SparseArray *SparseArrayExpandingArray(SparseArray *sarray)
+{
+	// Expanding a child sarray has undefined results.
+	assert(sarray->refCount == 1);
+	SparseArray *new = calloc(1, sizeof(SparseArray));
+	new->refCount = 1;
+	new->shift = sarray->shift;
+	new->mask = sarray->mask;
+	void **newData = malloc(DATA_SIZE(sarray) * sizeof(void*));
+	for(unsigned i=0 ; i<=MAX_INDEX(sarray) ; i++)
+	{
+		newData[i] = &EmptyArray;
+	}
+	new->data = sarray->data;
+	// new is now an exact copy of sarray.
+	newData[0] = new;
+	sarray->data = newData;
+	// Now, any lookup in sarray for any value less than its capacity will have
+	// all non-zero values shifted away, resulting in 0.  All lookups will
+	// therefore go to the new sarray.
+	sarray->shift += base_shift;
+	// Finally, set the mask to the correct value.  Now all lookups should work.
+	sarray->mask <<= base_shift;
+	return new;
+}
+
+static void *SparseArrayFind(SparseArray * sarray, uint32_t * index)
+{
+	uint32_t j = MASK_INDEX((*index));
+	uint32_t max = MAX_INDEX(sarray);
+	if (sarray->shift == 0)
+	{
+		while (j<=max)
+		{
+			if (sarray->data[j] != SARRAY_EMPTY)
+			{
+				return sarray->data[j];
+			}
+			(*index)++;
+			j++;
+		}
+	}
+	else while (j<max)
+	{
+		uint32_t zeromask = ~(sarray->mask >> base_shift);
+		while (j<max)
+		{
+			//Look in child nodes
+			if (sarray->data[j] != SARRAY_EMPTY)
+			{
+				void * ret = SparseArrayFind(sarray->data[j], index);
+				if (ret != SARRAY_EMPTY)
+				{
+					return ret;
+				}
+				// The recursive call will set index to the correct value for
+				// the next index, but won't update j
+			}
+			else
+			{
+				//Add 2^n to index so j is still correct
+				(*index) += 1<<sarray->shift;
+				//Zero off the next component of the index so we don't miss any.
+				*index &= zeromask;
+			}
+			//Go to the next child
+			j++;
+		}
+	}
+	return SARRAY_EMPTY;
+}
+
+PRIVATE void *SparseArrayNext(SparseArray * sarray, uint32_t * idx)
+{
+	(*idx)++;
+	return SparseArrayFind(sarray, idx);
+}
+
+PRIVATE void SparseArrayInsert(SparseArray * sarray, uint32_t index, void *value)
+{
+	if (sarray->shift > 0)
+	{
+		uint32_t i = MASK_INDEX(index);
+		SparseArray *child = sarray->data[i];
+		if(&EmptyArray == child)
+		{
+			// Insert missing nodes
+			SparseArray * newsarray = calloc(1, sizeof(SparseArray));
+			newsarray->refCount = 1;
+			if (base_shift >= sarray->shift)
+			{
+				newsarray->shift = 0;
+			}
+			else
+			{
+				newsarray->shift = sarray->shift - base_shift;
+			}
+			newsarray->mask = sarray->mask >> base_shift;
+			init_pointers(newsarray);
+			sarray->data[i] = newsarray;
+			child = newsarray;
+		}
+		else if (child->refCount > 1)
+		{
+			// Copy the copy-on-write part of the tree
+			sarray->data[i] = SparseArrayCopy(child);
+			SparseArrayDestroy(child);
+			child = sarray->data[i];
+		}
+		SparseArrayInsert(child, index, value);
+	}
+	else
+	{
+		sarray->data[index & sarray->mask] = value;
+	}
+}
+
+PRIVATE SparseArray *SparseArrayCopy(SparseArray * sarray)
+{
+	SparseArray *copy = calloc(1, sizeof(SparseArray));
+	copy->refCount = 1;
+	copy->shift = sarray->shift;
+	copy->mask = sarray->mask;
+	copy->data = malloc(sizeof(void*) * DATA_SIZE(sarray));
+	memcpy(copy->data, sarray->data, sizeof(void*) * DATA_SIZE(sarray));
+	// If the sarray has children, increase their refcounts and link them
+	if (sarray->shift > 0)
+	{
+		for (unsigned int i = 0 ; i<=MAX_INDEX(sarray); i++)
+		{
+			SparseArray *child = copy->data[i];
+			__sync_fetch_and_add(&child->refCount, 1);
+			// Non-lazy copy.  Uncomment if debugging 
+			// copy->data[i] = SparseArrayCopy(copy->data[i]);
+		}
+	}
+	return copy;
+}
+
+PRIVATE void SparseArrayDestroy(SparseArray * sarray)
+{
+	// Don't really delete this sarray if its ref count is > 0
+	if (sarray == &EmptyArray || 
+		(__sync_sub_and_fetch(&sarray->refCount, 1) > 0))
+ 	{
+		return;
+	}
+
+	if(sarray->shift > 0)
+	{
+		uint32_t max = (sarray->mask >> sarray->shift) + 1;
+		for(uint32_t i=0 ; i<max ; i++)
+		{
+			SparseArrayDestroy((SparseArray*)sarray->data[i]);
+		}
+	}
+	free(sarray->data);
+	free(sarray);
+}
+
diff --git a/third_party/libobjc/sarray2.h b/third_party/libobjc/sarray2.h
new file mode 100644
index 0000000000000000000000000000000000000000..ce1d41a850469233e6a9feee0fd4f299d0d91851
--- /dev/null
+++ b/third_party/libobjc/sarray2.h
@@ -0,0 +1,139 @@
+/**
+ * Sparse Array
+ *
+ * Author: David Chisnall
+ * 
+ * License: See COPYING.MIT
+ *
+ */
+
+#ifndef _SARRAY_H_INCLUDED_
+#define _SARRAY_H_INCLUDED_
+#include <stdint.h>
+#include <stdlib.h>
+#include "visibility.h"
+
+/**
+ * Sparse arrays, used to implement dispatch tables.  Current implementation is
+ * quite RAM-intensive and could be optimised.  Maps 32-bit integers to pointers.
+ *
+ * Note that deletion from the array is not supported.  This allows accesses to
+ * be done without locking; the worst that can happen is that the caller gets
+ * an old value (and if this is important to you then you should be doing your
+ * own locking).  For this reason, you should be very careful when deleting a
+ * sparse array that there are no references to it held by other threads.
+ */
+typedef struct 
+{
+	/**
+	 * Mask value applied to the index when generating an index in this
+	 * sub-array.
+	 */
+	uint32_t mask;
+	/**
+	 * Number of bits that the masked value should be right shifted by to get
+	 * the index in the subarray.  If this value is greater than zero, then the
+	 * value in the array is another SparseArray*.
+	 */
+	uint32_t shift;
+	/**
+	 * The reference count for this.  Used for copy-on-write.  When making a
+	 * copy of a sparse array, we only copy the root node, and increment the
+	 * reference count of the remaining nodes.  When modifying any leaf node,
+	 * we copy if its reference count is greater than one.
+	 */
+	uint32_t refCount;
+	/**
+	 * The data stored in this sparse array node.
+	 */
+	void ** data;
+} SparseArray;
+
+/**
+ * Turn an index in the array into an index in the current depth.
+ */
+#define MASK_INDEX(index) \
+	((index & sarray->mask) >> sarray->shift)
+
+#define SARRAY_EMPTY ((void*)0)
+/**
+ * Look up the specified value in the sparse array.  This is used in message
+ * dispatch and so has been put in the header to allow compilers to inline it,
+ * even though this breaks the abstraction.
+ */
+static inline void* SparseArrayLookup(SparseArray * sarray, uint32_t index)
+{
+	// This unrolled version of the commented-out segment below only works with
+	// sarrays that use one-byte leaves.  It's really ugly, but seems to be faster.
+	// With this version, we get the same performance as the old GNU code, but
+	// with about half the memory usage.
+	uint32_t i = index;
+	switch (sarray->shift)
+	{
+		default: UNREACHABLE("broken sarray");
+		case 0:
+			return sarray->data[i & 0xff];
+		case 8:
+			return 
+				((SparseArray*)sarray->data[(i & 0xff00)>>8])->data[(i & 0xff)];
+		case 16:
+			return 
+				((SparseArray*)((SparseArray*)
+					sarray->data[(i & 0xff0000)>>16])->
+						data[(i & 0xff00)>>8])->data[(i & 0xff)];
+		case 24:
+			return 
+				((SparseArray*)((SparseArray*)((SparseArray*)
+					sarray->data[(i & 0xff000000)>>24])->
+						data[(i & 0xff0000)>>16])->
+							data[(i & 0xff00)>>8])->data[(i & 0xff)];
+	}
+	/*
+	while(sarray->shift > 0)
+	{
+		uint32_t i = MASK_INDEX(index);
+		sarray = (SparseArray*) sarray->data[i];
+	}
+	uint32_t i = index & sarray->mask;
+	return sarray->data[i];
+	*/
+}
+/**
+ * Create a new sparse array.
+ */
+SparseArray *SparseArrayNew();
+/**
+ * Creates a new sparse array with the specified capacity.  The depth indicates
+ * the number of bits to use for the key.  Must be a value between 8 and 32 and
+ * should ideally be a multiple of base_shift.
+ */
+SparseArray *SparseArrayNewWithDepth(uint32_t depth);
+/**
+ * Returns a new sparse array created by adding this one as the first child
+ * node in an expanded one.
+ */
+SparseArray *SparseArrayExpandingArray(SparseArray *sarray);
+/**
+ * Insert a value at the specified index.
+ */
+void SparseArrayInsert(SparseArray * sarray, uint32_t index, void * value);
+/**
+ * Destroy the sparse array.  Note that calling this while other threads are
+ * performing lookups is guaranteed to break.
+ */
+void SparseArrayDestroy(SparseArray * sarray);
+/**
+ * Iterate through the array.  Returns the next non-NULL value after index and
+ * sets index to the following value.  For example, an array containing values
+ * at 0 and 10 will, if called with index set to 0 first return the value at 0
+ * and set index to 1.  A subsequent call with index set to 1 will return the
+ * value at 10 and set index to 11.
+ */
+void * SparseArrayNext(SparseArray * sarray, uint32_t * index);
+
+/**
+ * Creates a copy of the sparse array.
+ */
+SparseArray *SparseArrayCopy(SparseArray * sarray);
+
+#endif //_SARRAY_H_INCLUDED_
diff --git a/third_party/libobjc/selector.h b/third_party/libobjc/selector.h
new file mode 100644
index 0000000000000000000000000000000000000000..116d0b9bdfea6a5a2c0b35fa7ac513c58363cdc5
--- /dev/null
+++ b/third_party/libobjc/selector.h
@@ -0,0 +1,82 @@
+#ifndef OBJC_SELECTOR_H_INCLUDED
+#define OBJC_SELECTOR_H_INCLUDED
+/**
+ * Structure used to store the types for a selector.  This allows for a quick
+ * test to see whether a selector is polymorphic and allows enumeration of all
+ * type encodings for a given selector.
+ *
+ * This is the same size as an objc_selector, so we can allocate them from the
+ * objc_selector pool.
+ *
+ * Note: For ABI v10, we can probably do something a bit more sensible here and
+ * make selectors into a linked list.
+ */
+struct sel_type_list
+{
+	const char *value;
+	struct sel_type_list *next;
+};
+
+/**
+ * Structure used to store selectors in the list.
+ */
+struct objc_selector
+{
+	union
+	{
+		/**
+		 * The name of this selector.  Used for unregistered selectors.
+		 */
+		const char *name;
+		/**
+		 * The index of this selector in the selector table.  When a selector
+		 * is registered with the runtime, its name is replaced by an index
+		 * uniquely identifying this selector.  The index is used for dispatch.
+		 */
+		uintptr_t index;
+	};
+	/**
+	 * The Objective-C type encoding of the message identified by this selector.
+	 */
+	const char * types;
+};
+
+/**
+ * Returns the untyped variant of a selector.
+ */
+__attribute__((unused))
+static uint32_t get_untyped_idx(SEL aSel)
+{
+	SEL untyped = sel_registerTypedName_np(sel_getName(aSel), 0);
+	return untyped->index;
+}
+
+__attribute__((unused))
+static SEL sel_getUntyped(SEL aSel)
+{
+	return sel_registerTypedName_np(sel_getName(aSel), 0);
+}
+
+/**
+ * Returns whether a selector is mapped.  
+ */
+BOOL isSelRegistered(SEL sel);
+
+/**
+ * Registers the selector.  This selector may be returned later, so it must not
+ * be freed.
+ */
+SEL objc_register_selector(SEL aSel);
+
+/**
+ * SELECTOR() macro to work around the fact that GCC hard-codes the type of
+ * selectors.  This is functionally equivalent to @selector(), but it ensures
+ * that the selector has the type that the runtime uses for selectors.
+ */
+#ifdef __clang__
+#define SELECTOR(x) @selector(x)
+#else
+#define SELECTOR(x) (SEL)@selector(x)
+#endif
+
+#endif // OBJC_SELECTOR_H_INCLUDED
diff --git a/third_party/libobjc/selector_table.c b/third_party/libobjc/selector_table.c
new file mode 100644
index 0000000000000000000000000000000000000000..d75e1c494c0c3667d36eabf682d843f88b46909e
--- /dev/null
+++ b/third_party/libobjc/selector_table.c
@@ -0,0 +1,632 @@
+/**
+ * Handle selector uniquing.
+ *
+ * When building, you may define TYPE_DEPENDENT_DISPATCH to enable message
+ * sends to depend on their types.
+ */
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <ctype.h>
+#include "lock.h"
+#include "sarray2.h"
+#include "objc/runtime.h"
+#include "method_list.h"
+#include "class.h"
+#include "selector.h"
+#include "visibility.h"
+
+#ifdef TYPE_DEPENDENT_DISPATCH
+#	define TDD(x) x
+#else
+#	define TDD(x)
+#endif
+
+#define fprintf(...)
+
+
+// Define the pool allocator for selectors.  This is a simple bump-the-pointer
+// allocator for low-overhead allocation.
+#define POOL_NAME selector
+#define POOL_TYPE struct objc_selector
+#include "pool.h"
+
+
+/**
+ * The number of selectors currently registered.  When a selector is
+ * registered, its name field is replaced with its index in the selector_list
+ * array.
+ */
+static uint32_t selector_count = 1;
+/**
+ * Mapping from selector numbers to selector names.
+ */
+PRIVATE SparseArray *selector_list  = NULL;
+
+// Get the functions for string hashing
+#include "string_hash.h"
+
+PRIVATE inline BOOL isSelRegistered(SEL sel)
+{
+	if ((uintptr_t)sel->name < (uintptr_t)selector_count)
+	{
+		return YES;
+	}
+	return NO;
+}
+
+static const char *sel_getNameNonUnique(SEL sel)
+{
+	const char *name = sel->name;
+	if (isSelRegistered(sel))
+	{
+		struct sel_type_list * list =
+			SparseArrayLookup(selector_list, sel->index);
+		name = (list == NULL) ? NULL : list->value;
+	}
+	if (NULL == name)
+	{
+		name = "";
+	}
+	return name;
+}
+
+/**
+ * Skip anything in a type encoding that is irrelevant to the comparison
+ * between selectors, including type qualifiers and argframe info.
+ */
+static const char *skip_irrelevant_type_info(const char *t)
+{
+	switch (*t)
+	{
+		default: return t;
+		case 'r': case 'n': case 'N': case 'o': case 'O': case 'R':
+		case 'V': case '!': case '0'...'9':
+			return skip_irrelevant_type_info(t+1);
+	}
+}
+
+static BOOL selector_types_equal(const char *t1, const char *t2)
+{
+	if (t1 == NULL || t2 == NULL) { return t1 == t2; }
+
+	while (('\0' != *t1) && ('\0' != *t1))
+	{
+		t1 = skip_irrelevant_type_info(t1);
+		t2 = skip_irrelevant_type_info(t2);
+		// This is a really ugly hack.  For some stupid reason, the people
+		// designing Objective-C type encodings decided to allow * as a
+		// shorthand for char*, because strings are 'special'.  Unfortunately,
+		// FSF GCC generates "*" for @encode(BOOL*), while Clang and Apple GCC
+		// generate "^c" or "^C" (depending on whether BOOL is declared
+		// unsigned).  
+		//
+		// The correct fix is to remove * completely from type encodings, but
+		// unfortunately my time machine is broken so I can't travel to 1986
+		// and apply a cluebat to those responsible.
+		if ((*t1 == '*') && (*t2 != '*'))
+		{
+			if (*t2 == '^' && (((*(t2+1) == 'C') || (*(t2+2) == 'c'))))
+			{
+				t2++;
+			}
+			else
+			{
+				return NO;
+			}
+		}
+		else if ((*t2 == '*') && (*t1 != '*'))
+		{
+			if (*t1 == '^' && (((*(t1+1) == 'C') || (*(t1+1) == 'c'))))
+			{
+				t1++;
+			}
+			else
+			{
+				return NO;
+			}
+		}
+		else if (*t1 != *t2)
+		{
+			return NO;
+		}
+
+		if ('\0' != *t1) { t1++; }
+		if ('\0' != *t2) { t2++; }
+	}
+	return YES;
+}
+
+#ifdef TYPE_DEPENDENT_DISPATCH
+
+static BOOL selector_types_equivalent(const char *t1, const char *t2)
+{
+	// We always treat untyped selectors as having the same type as typed
+	// selectors, for dispatch purposes.
+	if (t1 == NULL || t2 == NULL) { return YES; }
+
+	return selector_types_equal(t1, t2);
+}
+#endif
+
+/**
+ * Compare whether two selectors are identical.
+ */
+static int selector_identical(const void *k,
+                              const SEL value)
+{
+	SEL key = (SEL)k;
+	fprintf(stderr, "Comparing %s %s, %s %s\n", sel_getNameNonUnique(key), sel_getNameNonUnique(value), sel_getType_np(key), sel_getType_np(value));
+	return string_compare(sel_getNameNonUnique(key), sel_getNameNonUnique(value)) &&
+		selector_types_equal(sel_getType_np(key), sel_getType_np(value));
+}
+
+/**
+ * Compare selectors based on whether they are treated as equivalent for the
+ * purpose of dispatch.
+ */
+static int selector_equal(const void *k,
+                            const SEL value)
+{
+#ifdef TYPE_DEPENDENT_DISPATCH
+	return selector_identical(k, value);
+#else
+	SEL key = (SEL)k;
+	return string_compare(sel_getNameNonUnique(key), sel_getNameNonUnique(value));
+#endif
+}
+
+/**
+ * Hash a selector.
+ */
+static inline uint32_t hash_selector(const void *s)
+{
+	SEL sel = (SEL)s;
+	uint32_t hash = 5381;
+	const char *str = sel_getNameNonUnique(sel);
+	uint32_t c;
+	while((c = (uint32_t)*str++))
+	{
+		hash = hash * 33 + c;
+	}
+#ifdef TYPE_DEPENDENT_DISPATCH
+	// We can't use all of the values in the type encoding for the hash,
+	// because our equality test is a bit more complex than simple string
+	// encoding (for example, * and ^C have to be considered equivalent, since
+	// they are both used as encodings for C strings in different situations)
+	if ((str = sel_getType_np(sel)))
+	{
+		while((c = (uint32_t)*str++))
+		{
+			switch (c)
+			{
+				case '@': case 'i': case 'I': case 'l': case 'L':
+				case 'q': case 'Q': case 's': case 'S': 
+				hash = hash * 33 + c;
+			}
+		}
+	}
+#endif
+	return hash;
+}
+
+#define MAP_TABLE_NAME selector
+#define MAP_TABLE_COMPARE_FUNCTION selector_identical
+#define MAP_TABLE_HASH_KEY hash_selector
+#define MAP_TABLE_HASH_VALUE hash_selector
+#include "hash_table.h"
+/**
+ * Table of registered selector.  Maps from selector to selector.
+ */
+static selector_table *sel_table;
+
+/**
+ * Lock protecting the selector table.
+ */
+mutex_t selector_table_lock;
+
+
+/**
+ * Resizes the dtables to ensure that they can store as many selectors as
+ * exist.
+ */
+void objc_resize_dtables(uint32_t);
+
+/**
+ * Create data structures to store selectors.
+ */
+PRIVATE void init_selector_tables()
+{
+	selector_list = SparseArrayNew();
+	INIT_LOCK(selector_table_lock);
+	selector_initialize(&sel_table, 4096);
+}
+
+static SEL selector_lookup(const char *name, const char *types)
+{
+	struct objc_selector sel = {{name}, types};
+	return selector_table_get(sel_table, &sel);
+}
+static inline void add_selector_to_table(SEL aSel, int32_t uid, uint32_t idx)
+{
+	//fprintf(stderr, "Sel %s uid: %d, idx: %d, hash: %d\n", sel_getNameNonUnique(aSel), uid, idx, hash_selector(aSel));
+	struct sel_type_list *typeList =
+		(struct sel_type_list *)selector_pool_alloc();
+	typeList->value = aSel->name;
+	typeList->next = 0;
+	// Store the name.
+	SparseArrayInsert(selector_list, idx, typeList);
+	// Store the selector.
+	selector_insert(sel_table, aSel);
+	// Set the selector's name to the uid.
+	aSel->name = (const char*)(uintptr_t)uid;
+}
+/**
+ * Really registers a selector.  Must be called with the selector table locked.
+ */
+static inline void register_selector_locked(SEL aSel)
+{
+	uintptr_t idx = selector_count++;
+	if (NULL == aSel->types)
+	{
+		fprintf(stderr, "Registering selector %d %s\n", (int)idx, sel_getNameNonUnique(aSel));
+		add_selector_to_table(aSel, idx, idx);
+		objc_resize_dtables(selector_count);
+		return;
+	}
+	SEL untyped = selector_lookup(aSel->name, 0);
+	// If this has a type encoding, store the untyped version too.
+	if (untyped == NULL)
+	{
+		untyped = selector_pool_alloc();
+		untyped->name = aSel->name;
+		untyped->types = 0;
+		fprintf(stderr, "Registering selector %d %s\n", (int)idx, sel_getNameNonUnique(aSel));
+		add_selector_to_table(untyped, idx, idx);
+		// If we are in type dependent dispatch mode, the uid for the typed
+		// and untyped versions will be different
+		idx++; selector_count++;
+	}
+	else
+	{
+		// Make sure we only store one name
+		aSel->name = sel_getNameNonUnique(untyped);
+	}
+	uintptr_t uid = (uintptr_t)untyped->name;
+	TDD(uid = idx);
+	fprintf(stderr, "Registering typed selector %d %s %s\n", (int)uid, sel_getNameNonUnique(aSel), sel_getType_np(aSel));
+	add_selector_to_table(aSel, uid, idx);
+
+	// Add this set of types to the list.
+	// This is quite horrible.  Most selectors will only have one type
+	// encoding, so we're wasting a lot of memory like this.
+	struct sel_type_list *typeListHead =
+		SparseArrayLookup(selector_list, untyped->index);
+	struct sel_type_list *typeList =
+		(struct sel_type_list *)selector_pool_alloc();
+	typeList->value = aSel->types;
+	typeList->next = typeListHead->next;
+	typeListHead->next = typeList;
+	objc_resize_dtables(selector_count);
+}
+/**
+ * Registers a selector.  This assumes that the argument is never deallocated.
+ */
+PRIVATE SEL objc_register_selector(SEL aSel)
+{
+	if (isSelRegistered(aSel))
+	{
+		return aSel;
+	}
+	// Check that this isn't already registered, before we try
+	SEL registered = selector_lookup(aSel->name, aSel->types);
+	if (NULL != registered && selector_equal(aSel, registered))
+	{
+		aSel->name = registered->name;
+		return registered;
+	}
+	LOCK(&selector_table_lock);
+	register_selector_locked(aSel);
+	UNLOCK(&selector_table_lock);
+	return aSel;
+}
+
+/**
+ * Registers a selector by copying the argument.
+ */
+static SEL objc_register_selector_copy(SEL aSel, BOOL copyArgs)
+{
+	// If an identical selector is already registered, return it.
+	SEL copy = selector_lookup(aSel->name, aSel->types);
+	//fprintf(stderr, "Checking if old selector is registered: %d (%d)\n", NULL != copy ? selector_equal(aSel, copy) : 0, ((NULL != copy) && selector_equal(aSel, copy)));
+	if ((NULL != copy) && selector_identical(aSel, copy))
+	{
+	//fprintf(stderr, "Not adding new copy\n");
+		return copy;
+	}
+	LOCK_FOR_SCOPE(&selector_table_lock);
+	copy = selector_lookup(aSel->name, aSel->types);
+	if (NULL != copy && selector_identical(aSel, copy))
+	{
+		return copy;
+	}
+	// Create a copy of this selector.
+	copy = selector_pool_alloc();
+	copy->name = copyArgs ? strdup(aSel->name) : aSel->name;
+	copy->types = (NULL == aSel->types) ? NULL :
+	                 (copyArgs ? strdup(aSel->types) : aSel->types);
+	// Try to register the copy as the authoritative version
+	register_selector_locked(copy);
+	return copy;
+}
+
+PRIVATE uint32_t sel_nextTypeIndex(uint32_t untypedIdx, uint32_t idx)
+{
+	struct sel_type_list *list =
+		SparseArrayLookup(selector_list, untypedIdx);
+
+	if (NULL == list) { return 0; }
+
+	const char *selName = list->value;
+	list = list->next;
+	BOOL found = untypedIdx == idx;
+	while (NULL != list)
+	{
+		SEL sel = selector_lookup(selName, list->value);
+		if (sel->index == untypedIdx) { return 0; }
+		if (found)
+		{
+			return sel->index;
+		}
+		found = (sel->index == idx);
+	}
+	return 0;
+}
+
+/**
+ * Public API functions.
+ */
+
+const char *sel_getName(SEL sel)
+{
+	if (NULL == sel) { return "<null selector>"; }
+	const char *name = sel->name;
+	if (isSelRegistered(sel))
+	{
+		struct sel_type_list * list =
+			SparseArrayLookup(selector_list, sel->index);
+		name = (list == NULL) ? NULL : list->value;
+	}
+	else
+	{
+		SEL old = selector_lookup(sel->name, sel->types);
+		if (NULL != old)
+		{
+			return sel_getName(old);
+		}
+	}
+	if (NULL == name)
+	{
+		name = "";
+	}
+	return name;
+}
+
+SEL sel_getUid(const char *selName)
+{
+	return sel_registerName(selName);
+}
+
+BOOL sel_isEqual(SEL sel1, SEL sel2)
+{
+	if ((0 == sel1) || (0 == sel2))
+	{
+		return sel1 == sel2;
+	}
+	if (sel1->name == sel2->name)
+	{
+		return YES;
+	}
+	// Otherwise, do a slow compare
+	return string_compare(sel_getNameNonUnique(sel1), sel_getNameNonUnique(sel2)) TDD(&&
+			(sel1->types == NULL || sel2->types == NULL ||
+		selector_types_equivalent(sel_getType_np(sel1), sel_getType_np(sel2))));
+}
+
+SEL sel_registerName(const char *selName)
+{
+	if (NULL == selName) { return NULL; }
+	struct objc_selector sel = {{selName}, 0};
+	return objc_register_selector_copy(&sel, YES);
+}
+
+SEL sel_registerTypedName_np(const char *selName, const char *types)
+{
+	if (NULL == selName) { return NULL; }
+	struct objc_selector sel = {{selName}, types};
+	return objc_register_selector_copy(&sel, YES);
+}
+
+const char *sel_getType_np(SEL aSel)
+{
+	if (NULL == aSel) { return NULL; }
+	return aSel->types;
+}
+
+
+unsigned sel_copyTypes_np(const char *selName, const char **types, unsigned count)
+{
+	if (NULL == selName) { return 0; }
+	SEL untyped = selector_lookup(selName, 0);
+	if (untyped == NULL) { return 0; }
+
+	struct sel_type_list *l =
+		SparseArrayLookup(selector_list, (uint32_t)(uintptr_t)untyped->name);
+	// Skip the head, which just contains the name, not the types.
+	l = l->next;
+
+	if (count == 0)
+	{
+		while (NULL != l)
+		{
+			count++;
+			l = l->next;
+		}
+		return count;
+	}
+
+	unsigned found = 0;
+	while (NULL != l) 
+	{
+		if (found<count)
+		{
+			types[found] = l->value;
+		}
+		found++;
+		l = l->next;
+	}
+	return found;
+}
+
+unsigned sel_copyTypedSelectors_np(const char *selName, SEL *const sels, unsigned count)
+{
+	if (NULL == selName) { return 0; }
+	SEL untyped = selector_lookup(selName, 0);
+	if (untyped == NULL) { return 0; }
+
+	struct sel_type_list *l =
+		SparseArrayLookup(selector_list, (uint32_t)(uintptr_t)untyped->name);
+	// Skip the head, which just contains the name, not the types.
+	l = l->next;
+
+	if (count == 0)
+	{
+		while (NULL != l)
+		{
+			count++;
+			l = l->next;
+		}
+		return count;
+	}
+
+	unsigned found = 0;
+	while (NULL != l && found<count)
+	{
+		sels[found++] = selector_lookup(selName, l->value);
+		l = l->next;
+	}
+	return found;
+}
+
+PRIVATE void objc_register_selectors_from_list(struct objc_method_list *l)
+{
+	for (int i=0 ; i<l->count ; i++)
+	{
+		Method m = &l->methods[i];
+		struct objc_selector sel = { {(const char*)m->selector}, m->types };
+		m->selector = objc_register_selector_copy(&sel, NO);
+	}
+}
+/**
+ * Register all of the (unregistered) selectors that are used in a class.
+ */
+PRIVATE void objc_register_selectors_from_class(Class class)
+{
+	for (struct objc_method_list *l=class->methods ; NULL!=l ; l=l->next)
+	{
+		objc_register_selectors_from_list(l);
+	}
+}
+PRIVATE void objc_register_selector_array(SEL selectors, unsigned long count)
+{
+	// GCC is broken and always sets the count to 0, so we ignore count until
+	// we can throw stupid and buggy compilers in the bin.
+	for (unsigned long i=0 ;  (NULL != selectors[i].name) ; i++)
+	{
+		objc_register_selector(&selectors[i]);
+	}
+}
+
+
+/**
+ * Legacy GNU runtime compatibility.
+ *
+ * All of the functions in this section are deprecated and should not be used
+ * in new code.
+ */
+#ifndef NO_LEGACY
+SEL sel_get_typed_uid (const char *name, const char *types)
+{
+	if (NULL == name) { return NULL; }
+	SEL sel = selector_lookup(name, types);
+	if (NULL == sel) { return sel_registerTypedName_np(name, types); }
+
+	struct sel_type_list *l =
+		SparseArrayLookup(selector_list, (uint32_t)(uintptr_t)sel->name);
+	// Skip the head, which just contains the name, not the types.
+	l = l->next;
+	if (NULL != l)
+	{
+		sel = selector_lookup(name, l->value);
+	}
+	return sel;
+}
+
+SEL sel_get_any_typed_uid (const char *name)
+{
+	if (NULL == name) { return NULL; }
+	SEL sel = selector_lookup(name, 0);
+	if (NULL == sel) { return sel_registerName(name); }
+
+	struct sel_type_list *l =
+		SparseArrayLookup(selector_list, (uint32_t)(uintptr_t)sel->name);
+	// Skip the head, which just contains the name, not the types.
+	l = l->next;
+	if (NULL != l)
+	{
+		sel = selector_lookup(name, l->value);
+	}
+	return sel;
+}
+
+SEL sel_get_any_uid (const char *name)
+{
+	return selector_lookup(name, 0);
+}
+
+SEL sel_get_uid(const char *name)
+{
+	return selector_lookup(name, 0);
+}
+
+const char *sel_get_name(SEL selector)
+{
+	return sel_getNameNonUnique(selector);
+}
+
+BOOL sel_is_mapped(SEL selector)
+{
+	return isSelRegistered(selector);
+}
+
+const char *sel_get_type(SEL selector)
+{
+	return sel_getType_np(selector);
+}
+
+SEL sel_register_name(const char *name)
+{
+	return sel_registerName(name);
+}
+
+SEL sel_register_typed_name(const char *name, const char *type)
+{
+	return sel_registerTypedName_np(name, type);
+}
+
+BOOL sel_eq(SEL s1, SEL s2)
+{
+	return sel_isEqual(s1, s2);
+}
+
+#endif // NO_LEGACY
diff --git a/third_party/libobjc/sendmsg2.c b/third_party/libobjc/sendmsg2.c
new file mode 100644
index 0000000000000000000000000000000000000000..0b026a8225d272c24c8b009fdb165ababb5302e0
--- /dev/null
+++ b/third_party/libobjc/sendmsg2.c
@@ -0,0 +1,409 @@
+#include "objc/runtime.h"
+#include "lock.h"
+#include "dtable.h"
+#include "selector.h"
+#include "loader.h"
+#include "objc/hooks.h"
+#include <stdint.h>
+#include <stdio.h>
+
+void objc_send_initialize(id object);
+
+static long long nil_method(id self, SEL _cmd) { return 0; }
+static long double nil_method_D(id self, SEL _cmd) { return 0; }
+static double nil_method_d(id self, SEL _cmd) { return 0; }
+static float nil_method_f(id self, SEL _cmd) { return 0; }
+
+static struct objc_slot nil_slot = { Nil, Nil, 0, 1, (IMP)nil_method };
+static struct objc_slot nil_slot_D = { Nil, Nil, 0, 1, (IMP)nil_method_D };
+static struct objc_slot nil_slot_d = { Nil, Nil, 0, 1, (IMP)nil_method_d };
+static struct objc_slot nil_slot_f = { Nil, Nil, 0, 1, (IMP)nil_method_f };
+
+typedef struct objc_slot *Slot_t;
+
+Slot_t objc_msg_lookup_sender(id *receiver, SEL selector, id sender);
+
+// Default implementations of the two new hooks.  Return NULL.
+static id objc_proxy_lookup_null(id receiver, SEL op) { return nil; }
+static Slot_t objc_msg_forward3_null(id receiver, SEL op) { return &nil_slot; }
+
+id (*objc_proxy_lookup)(id receiver, SEL op) = objc_proxy_lookup_null;
+Slot_t (*__objc_msg_forward3)(id receiver, SEL op) = objc_msg_forward3_null;
+
+#ifndef NO_SELECTOR_MISMATCH_WARNINGS
+static struct objc_slot* objc_selector_type_mismatch(Class cls, SEL
+		selector, Slot_t result)
+{
+	fprintf(stderr, "Calling [%s %c%s] with incorrect signature.  "
+			"Method has %s, selector has %s\n",
+			cls->name,
+			class_isMetaClass(cls) ? '+' : '-',
+			sel_getName(selector),
+			result->types,
+			sel_getType_np(selector));
+	return result;
+}
+#else
+static struct objc_slot* objc_selector_type_mismatch(Class cls, SEL
+		selector, Slot_t result)
+{
+	return result;
+}
+#endif
+
+struct objc_slot* (*_objc_selector_type_mismatch)(Class cls, SEL
+		selector, struct objc_slot *result) = objc_selector_type_mismatch;
+static 
+// Uncomment for debugging
+//__attribute__((noinline))
+__attribute__((always_inline))
+Slot_t objc_msg_lookup_internal(id *receiver,
+                                SEL selector, 
+                                id sender)
+{
+retry:;
+	Class class = classForObject((*receiver));
+	Slot_t result = objc_dtable_lookup(class->dtable, selector->index);
+	if (UNLIKELY(0 == result))
+	{
+		dtable_t dtable = dtable_for_class(class);
+		/* Install the dtable if it hasn't already been initialized. */
+		if (dtable == uninstalled_dtable)
+		{
+			objc_send_initialize(*receiver);
+			dtable = dtable_for_class(class);
+			result = objc_dtable_lookup(dtable, selector->index);
+		}
+		else
+		{
+			// Check again incase another thread updated the dtable while we
+			// weren't looking
+			result = objc_dtable_lookup(dtable, selector->index);
+		}
+		if (0 == result)
+		{
+			if (!isSelRegistered(selector))
+			{
+				objc_register_selector(selector);
+				// This should be a tail call, but GCC is stupid and won't let
+				// us tail call an always_inline function.
+				goto retry;
+			}
+			if ((result = objc_dtable_lookup(dtable, get_untyped_idx(selector))))
+			{
+				return _objc_selector_type_mismatch(class, selector, result);
+			}
+			id newReceiver = objc_proxy_lookup(*receiver, selector);
+			// If some other library wants us to play forwarding games, try
+			// again with the new object.
+			if (nil != newReceiver)
+			{
+				*receiver = newReceiver;
+				return objc_msg_lookup_sender(receiver, selector, sender);
+			}
+			if (0 == result)
+			{
+				result = __objc_msg_forward3(*receiver, selector);
+			}
+		}
+	}
+	return result;
+}
+
+PRIVATE
+IMP slowMsgLookup(id *receiver, SEL cmd)
+{
+	return objc_msg_lookup_sender(receiver, cmd, nil)->method;
+}
+
+PRIVATE void logInt(void *a)
+{
+	fprintf(stderr, "Value: %p\n", a);
+}
+
+Slot_t (*objc_plane_lookup)(id *receiver, SEL op, id sender) =
+	objc_msg_lookup_internal;
+
+Slot_t objc_msg_lookup_sender_non_nil(id *receiver, SEL selector, id sender)
+{
+	return objc_msg_lookup_internal(receiver, selector, sender);
+}
+
+/**
+ * New Objective-C lookup function.  This permits the lookup to modify the
+ * receiver and also supports multi-dimensional dispatch based on the sender.  
+ */
+Slot_t objc_msg_lookup_sender(id *receiver, SEL selector, id sender)
+{
+	// Returning a nil slot allows the caller to cache the lookup for nil too,
+	// although this is not particularly useful because the nil method can be
+	// inlined trivially.
+	if (UNLIKELY(*receiver == nil))
+	{
+		// Return the correct kind of zero, depending on the type encoding.
+		if (selector->types)
+		{
+			const char *t = selector->types;
+			// Skip type qualifiers
+			while ('r' == *t || 'n' == *t || 'N' == *t || 'o' == *t ||
+			       'O' == *t || 'R' == *t || 'V' == *t) 
+			{
+				t++;
+			}
+			switch (selector->types[0])
+			{
+				case 'D': return &nil_slot_D;
+				case 'd': return &nil_slot_d;
+				case 'f': return &nil_slot_f;
+			}
+		}
+		return &nil_slot;
+	}
+
+	/*
+	 * The self pointer is invalid in some code.  This test is disabled until
+	 * we can guarantee that it is not (e.g. with GCKit)
+	if (__builtin_expect(sender == nil
+		||
+		(sender->isa->info & (*receiver)->isa->info & _CLS_PLANE_AWARE),1))
+	*/
+	{
+		return objc_msg_lookup_internal(receiver, selector, sender);
+	}
+	// If we are in plane-aware code
+	void *senderPlaneID = *((void**)sender - 1);
+	void *receiverPlaneID = *((void**)receiver - 1);
+	if (senderPlaneID == receiverPlaneID)
+	{
+		return objc_msg_lookup_internal(receiver, selector, sender);
+	}
+	return objc_plane_lookup(receiver, selector, sender);
+}
+
+Slot_t objc_slot_lookup_super(struct objc_super *super, SEL selector)
+{
+	id receiver = super->receiver;
+	if (receiver)
+	{
+		Class class = super->class;
+		Slot_t result = objc_dtable_lookup(dtable_for_class(class),
+				selector->index);
+		if (0 == result)
+		{
+			Class class = classForObject(receiver);
+			// Dtable should always be installed in the superclass
+			// Unfortunately, some stupid code (PyObjC) decides to use this
+			// mechanism for everything 
+			if (dtable_for_class(class) == uninstalled_dtable)
+			{
+				if (class_isMetaClass(class))
+				{
+					objc_send_initialize(receiver);
+				}
+				else
+				{
+					objc_send_initialize((id)class);
+				}
+				objc_send_initialize((id)class);
+				return objc_slot_lookup_super(super, selector);
+			}
+			result = &nil_slot;
+		}
+		return result;
+	}
+	else
+	{
+		return &nil_slot;
+	}
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Profiling
+////////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Mutex used to protect non-thread-safe parts of the profiling subsystem.
+ */
+static mutex_t profileLock;
+/**
+ * File used for writing the profiling symbol table.
+ */
+static FILE *profileSymbols;
+/**
+ * File used for writing the profiling data.
+ */
+static FILE *profileData;
+
+struct profile_info 
+{
+	const char *module;
+	int32_t callsite;
+	IMP method;
+};
+
+static void profile_init(void)
+{
+	INIT_LOCK(profileLock);
+	profileSymbols = fopen("objc_profile.symbols", "a");
+	profileData = fopen("objc_profile.data", "a");
+	// Write markers indicating a new run.  
+	fprintf(profileSymbols, "=== NEW TRACE ===\n");
+	struct profile_info profile_data = { 0, 0, 0 };
+	fwrite(&profile_data, sizeof(profile_data), 1, profileData);
+}
+
+void objc_profile_write_symbols(char **symbols)
+{
+	if (NULL == profileData)
+	{
+		LOCK_RUNTIME_FOR_SCOPE();
+		if (NULL == profileData)
+		{
+			profile_init();
+		}
+	}
+	LOCK(&profileLock);
+	while(*symbols)
+	{
+		char *address = *(symbols++);
+		char *symbol = *(symbols++);
+		fprintf(profileSymbols, "%zx %s\n", (size_t)address, symbol);
+	}
+	UNLOCK(&profileLock);
+	fflush(profileSymbols);
+}
+
+/**
+ * Profiling version of the slot lookup.  This takes a unique ID for the module
+ * and the callsite as extra arguments.  The type of the receiver and the
+ * address of the resulting function are then logged to a file.  These can then
+ * be used to determine whether adding slot caching is worthwhile, and whether
+ * any of the resulting methods should be speculatively inlined.
+ */
+void objc_msg_profile(id receiver, IMP method,
+                      const char *module, int32_t callsite)
+{
+	// Initialize the logging lazily.  This prevents us from wasting any memory
+	// when we are not profiling.
+	if (NULL == profileData)
+	{
+		LOCK_RUNTIME_FOR_SCOPE();
+		if (NULL == profileData)
+		{
+			profile_init();
+		}
+	}
+	struct profile_info profile_data = { module, callsite, method };
+	fwrite(&profile_data, sizeof(profile_data), 1, profileData);
+}
+
+/**
+ * Looks up a slot without invoking any forwarding mechanisms
+ */
+Slot_t objc_get_slot(Class cls, SEL selector)
+{
+	Slot_t result = objc_dtable_lookup(cls->dtable, selector->index);
+	if (0 == result)
+	{
+		void *dtable = dtable_for_class(cls);
+		/* Install the dtable if it hasn't already been initialized. */
+		if (dtable == uninstalled_dtable)
+		{
+			dtable = dtable_for_class(cls);
+			result = objc_dtable_lookup(dtable, selector->index);
+		}
+		else
+		{
+			// Check again incase another thread updated the dtable while we
+			// weren't looking
+			result = objc_dtable_lookup(dtable, selector->index);
+		}
+		if (NULL == result)
+		{
+			if (!isSelRegistered(selector))
+			{
+				objc_register_selector(selector);
+				return objc_get_slot(cls, selector);
+			}
+			if ((result = objc_dtable_lookup(dtable, get_untyped_idx(selector))))
+			{
+				return _objc_selector_type_mismatch(cls, selector, result);
+			}
+		}
+	}
+	return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Public API
+////////////////////////////////////////////////////////////////////////////////
+
+BOOL class_respondsToSelector(Class cls, SEL selector)
+{
+	if (0 == selector || 0 == cls) { return NO; }
+
+	return NULL != objc_get_slot(cls, selector);
+}
+
+IMP class_getMethodImplementation(Class cls, SEL name)
+{
+	if ((Nil == cls) || (NULL == name)) { return (IMP)0; }
+	Slot_t slot = objc_get_slot(cls, name);
+	return NULL != slot ? slot->method : __objc_msg_forward2(nil, name);
+}
+
+IMP class_getMethodImplementation_stret(Class cls, SEL name)
+{
+	return class_getMethodImplementation(cls, name);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Legacy compatibility
+////////////////////////////////////////////////////////////////////////////////
+
+#ifndef NO_LEGACY
+/**
+ * Legacy message lookup function.
+ */
+BOOL __objc_responds_to(id object, SEL sel)
+{
+	return class_respondsToSelector(classForObject(object), sel);
+}
+
+IMP get_imp(Class cls, SEL selector)
+{
+	return class_getMethodImplementation(cls, selector);
+}
+
+/**
+ * Message send function that only ever worked on a small subset of compiler /
+ * architecture combinations.
+ */
+void *objc_msg_sendv(void)
+{
+	fprintf(stderr, "objc_msg_sendv() never worked correctly.  Don't use it.\n");
+	abort();
+}
+#endif
+/**
+ * Legacy message lookup function.  Does not support fast proxies or safe IMP
+ * caching.
+ */
+IMP objc_msg_lookup(id receiver, SEL selector)
+{
+	if (nil == receiver) { return (IMP)nil_method; }
+
+	id self = receiver;
+	Slot_t slot = objc_msg_lookup_internal(&self, selector, nil);
+	if (self != receiver)
+	{
+		slot = __objc_msg_forward3(receiver, selector);
+	}
+	return slot->method;
+}
+
+IMP objc_msg_lookup_super(struct objc_super *super, SEL selector)
+{
+	return objc_slot_lookup_super(super, selector)->method;
+}
diff --git a/third_party/libobjc/slot_pool.h b/third_party/libobjc/slot_pool.h
new file mode 100644
index 0000000000000000000000000000000000000000..68502ebe81388f5e32fa5e54acd6cab364183920
--- /dev/null
+++ b/third_party/libobjc/slot_pool.h
@@ -0,0 +1,18 @@
+#define POOL_NAME slot
+#define POOL_TYPE struct objc_slot
+#include "pool.h"
+
+/**
+ * Allocates a new slot and initialises it for this method.
+ */
+static inline struct objc_slot *new_slot_for_method_in_class(Method method, 
+                                                             Class class)
+{
+	struct objc_slot *slot = slot_pool_alloc();
+	slot->owner = class;
+	slot->types = method->selector->types;
+	slot->selector = method->selector;
+	slot->method = method->imp;
+	slot->version = 1;
+	return slot;
+}
diff --git a/third_party/libobjc/spinlock.h b/third_party/libobjc/spinlock.h
new file mode 100644
index 0000000000000000000000000000000000000000..f3dc2cfb296dce29624397f63bbe6f640777d29c
--- /dev/null
+++ b/third_party/libobjc/spinlock.h
@@ -0,0 +1,81 @@
+#ifdef __MINGW32__
+#include <windows.h>
+static unsigned sleep(unsigned seconds)
+{
+	Sleep(seconds*1000);
+	return 0;
+}
+#else
+#include <unistd.h>
+#endif
+
+/**
+ * Number of spinlocks.  This allocates one page on 32-bit platforms.
+ */
+#define spinlock_count (1<<10)
+static const int spinlock_mask = spinlock_count - 1;
+/**
+ * Integers used as spinlocks for atomic property access.
+ */
+extern int spinlocks[spinlock_count];
+/**
+ * Get a spin lock from a pointer.  We want to prevent lock contention between
+ * properties in the same object - if someone is stupid enough to be using
+ * atomic property access, they are probably stupid enough to do it for
+ * multiple properties in the same object.  We also want to try to avoid
+ * contention between the same property in different objects, so we can't just
+ * use the ivar offset.
+ */
+static inline volatile int *lock_for_pointer(void *ptr)
+{
+	intptr_t hash = (intptr_t)ptr;
+	// Most properties will be pointers, so disregard the lowest few bits
+	hash >>= sizeof(void*) == 4 ? 2 : 8;
+	intptr_t low = hash & spinlock_mask;
+	hash >>= 16;
+	hash |= low;
+	return spinlocks + (hash & spinlock_mask);
+}
+
+/**
+ * Unlocks the spinlock.  This is not an atomic operation.  We are only ever
+ * modifying the lowest bit of the spinlock word, so it doesn't matter if this
+ * is two writes because there is no contention among the high bit.  There is
+ * no possibility of contention among calls to this, because it may only be
+ * called by the thread owning the spin lock.
+ */
+inline static void unlock_spinlock(volatile int *spinlock)
+{
+	__sync_synchronize();
+	*spinlock = 0;
+}
+/**
+ * Attempts to lock a spinlock.  This is heavily optimised for the uncontended
+ * case, because property access should (generally) not be contended.  In the
+ * uncontended case, this is a single atomic compare and swap instruction and a
+ * branch.  Atomic CAS is relatively expensive (can be a pipeline flush, and
+ * may require locking a cache line in a cache-coherent SMP system, but it's a
+ * lot cheaper than a system call).
+ *
+ * If the lock is contended, then we just sleep and then try again after the
+ * other threads have run.  Note that there is no upper bound on the potential
+ * running time of this function, which is one of the great many reasons that
+ * using atomic accessors is a terrible idea, but in the common case it should
+ * be very fast.
+ */
+inline static void lock_spinlock(volatile int *spinlock)
+{
+	int count = 0;
+	// Set the spin lock value to 1 if it is 0.
+	while(!__sync_bool_compare_and_swap(spinlock, 0, 1))
+	{
+		count++;
+		if (0 == count % 10)
+		{
+			// If it is already 1, let another thread play with the CPU for a
+			// bit then try again.
+			sleep(0);
+		}
+	}
+}
+
diff --git a/third_party/libobjc/statics_loader.c b/third_party/libobjc/statics_loader.c
new file mode 100644
index 0000000000000000000000000000000000000000..6b2b1d40a2660cc7fd4817ff5ddffe8ce5aa8326
--- /dev/null
+++ b/third_party/libobjc/statics_loader.c
@@ -0,0 +1,72 @@
+#include <string.h>
+#include <stdio.h>
+#include "objc/runtime.h"
+#include "module.h"
+#include "constant_string.h"
+#include "visibility.h"
+
+#define BUFFER_TYPE struct objc_static_instance_list
+#include "buffer.h"
+
+static BOOL try_init_statics(struct objc_static_instance_list *statics)
+{
+	const char *class_name = statics->class_name;
+
+	// This is a horrible hack.
+	//
+	// Very bad things happen when you have more than one constant string class
+	// used in a program.  Unfortunately, GCC defaults to using
+	// NXConstantString, and if you forget to specify
+	// -fconstant-string-class=NSConstantString for some compilation units then
+	// you will end up with some NSConstantString instances and some
+	// NXConstantString instances.  This is a mess.  We hack around this by
+	// silently assuming that the user meant NSConstantString when they said
+	// NXConstantString if NSConstantString is set as the constant string class
+	// in string_class.h or by an external -D flag.
+	if (strcmp(class_name, "NXConstantString") == 0)
+	{
+		class_name = CONSTANT_STRING_CLASS;
+	}
+
+	Class class = (Class)objc_getClass(class_name);
+
+	if (Nil == class)
+	{
+		return NO;
+	}
+	for (id *instance=statics->instances ; nil!=*instance ; instance++)
+	{
+		(*instance)->isa = class;
+	}
+	return YES;
+}
+PRIVATE void objc_init_statics(struct objc_static_instance_list *statics)
+{
+	if (!try_init_statics(statics))
+	{
+		set_buffered_object_at_index(statics, buffered_objects++);
+	}
+}
+
+PRIVATE void objc_init_buffered_statics(void)
+{
+	BOOL shouldReshuffle = NO;
+
+	for (unsigned i=0 ; i<buffered_objects ; i++)
+	{
+		struct objc_static_instance_list *c = buffered_object_at_index(i);
+		if (NULL != c)
+		{
+			if (try_init_statics(c))
+			{
+				set_buffered_object_at_index(NULL, i);
+				shouldReshuffle = YES;
+			}
+		}
+	}
+
+	if (shouldReshuffle)
+	{
+		compact_buffer();
+	}
+}
diff --git a/third_party/libobjc/string_hash.h b/third_party/libobjc/string_hash.h
new file mode 100644
index 0000000000000000000000000000000000000000..d86ed0bf0df365caea4c421c8790fb6ea67fe6eb
--- /dev/null
+++ b/third_party/libobjc/string_hash.h
@@ -0,0 +1,34 @@
+#include <string.h>
+#include <stdint.h>
+
+/**
+ * Efficient string hash function.
+ */
+__attribute__((unused))
+static uint32_t string_hash(const char *str)
+{
+	uint32_t hash = 0;
+	int32_t c;
+	while ((c = *str++))
+	{
+		hash = c + (hash << 6) + (hash << 16) - hash;
+	}
+	return hash;
+}
+
+/**
+ * Test two strings for equality.
+ */
+__attribute__((unused))
+static int string_compare(const char *str1, const char *str2)
+{
+	if (str1 == str2)
+	{
+		return 1;
+	}
+	if (str1 == NULL || str2 == NULL) 
+	{
+		return 0;
+	}
+	return strcmp(str1, str2) == 0;
+}
diff --git a/third_party/libobjc/toydispatch.c b/third_party/libobjc/toydispatch.c
new file mode 100644
index 0000000000000000000000000000000000000000..c6c697037adaa1c689c864470a1463d5a026d849
--- /dev/null
+++ b/third_party/libobjc/toydispatch.c
@@ -0,0 +1,240 @@
+#include <pthread.h>
+#include <stdlib.h>
+#define __TOY_DISPATCH__
+#include "objc/toydispatch.h"
+
+/**
+ * Amount of total space in the ring buffer.  Must be a power of two.
+ */
+#define RING_BUFFER_SIZE 32
+/**
+ * Mask for converting a free-running counters into ring buffer indexes.
+ */
+#define RING_BUFFER_MASK (RING_BUFFER_SIZE - 1)
+
+struct dispatch_queue
+{
+	/**
+	 * Reference count for this queue.
+	 */
+	int refcount;
+	/**
+	 * Spin lock value.  Set to 1 when the queue is locked.  This allows
+	 * multiple threads to write to the queue but only one to read from it.
+	 * Reading and writing can happen concurrently, but writing requires
+	 * acquisition of this lock.
+	 */
+	volatile int spinlock;
+	/**
+	 * Producer free-running counter.  Incremented every time that a new item
+	 * is inserted into the ring buffer.
+	 */
+	unsigned int producer;
+	/**
+	 * Consumer free-running counter.  Incremented every time that an item is
+	 * removed from the buffer.
+	 */
+	unsigned int consumer;
+	/**
+	 * Mutex used to protect the condition variable.
+	 */
+	pthread_mutex_t mutex;
+	/**
+	 * Condition variable used in blocking mode.  The consumer thread will
+	 * sleep on this condition variable when the queue has been empty for a
+	 * little while.  The next producer thread to insert something will poke
+	 * the condition variable on any empty->non-empty transition.
+	 */
+	pthread_cond_t conditionVariable;
+	/**
+	 * Ring buffer containing functions and data to be executed by the
+	 * consumer.
+	 */
+	struct
+	{
+		dispatch_function_t function;
+		void *data;
+	} ring_buffer[RING_BUFFER_SIZE];
+};
+
+/**
+ * Check how much space is in the queue.  The number of used elements in the
+ * queue is always equal to producer - consumer.   Producer will always
+ * overflow before consumer (because you can't remove objects that have not
+ * been inserted.  In this case, the subtraction will be something along the
+ * lines of (0 - (2^32 - 14)).  This will be -(2^32 - 14), however this value
+ * can't be represented in a 32-bit integer and so will overflow to 14, giving
+ * the correct result, irrespective of overflow.  
+ */
+#define SPACE(q) (RING_BUFFER_SIZE - (q->producer - q->consumer))
+/**
+ * The buffer is full if there is no space in it.
+ */
+#define ISFULL(q) (SPACE(q) == 0)
+/**
+ * The buffer is empty if there is no data in it.
+ */
+#define ISEMPTY(q) ((q->producer - q->consumer) == 0)
+/**
+ * Converting the free running counters to array indexes is a masking
+ * operation.  For this to work, the buffer size must be a power of two.
+ * RING_BUFFER_MASK = RING_BUFFER_SIZE - 1.  If RING_BUFFER_SIZE is 256, we want the lowest 8
+ * bits of the index, which is obtained by ANDing the value with 255.  Any
+ * power of two may be selected.  Non power-of-two values could be used if a
+ * more complex mapping operation were chosen, but this one is nice and cheap.
+ */
+#define MASK(index) ((index) & RING_BUFFER_MASK)
+
+/**
+ * Lock the queue.  This uses a very lightweight, nonrecursive, spinlock.  It
+ * is expected that queue insertions will be relatively uncontended.
+ */
+inline static void lock_queue(dispatch_queue_t queue)
+{
+	// Set the spin lock value to 1 if it is 0.
+	while(!__sync_bool_compare_and_swap(&queue->spinlock, 0, 1))
+	{
+		// If it is already 1, let another thread play with the CPU for a bit
+		// then try again.
+		sched_yield();
+	}
+}
+
+/**
+ * Unlock the queue.  This doesn't need to be an atomic op; that will cause a
+ * complete pipeline flush on this thread and not actually buy us anything
+ * because at this point only one thread (this one) will do anything that will
+ * modify the variable.  The other threads will all be using atomic
+ * compare-and-exchange instructions which will fail because we already set it
+ * to 1.
+ */
+inline static void unlock_queue(dispatch_queue_t queue)
+{
+	queue->spinlock = 0;
+}
+
+/**
+ * Inserting an element into the queue involves the following steps:
+ *
+ * 1) Check that there is space in the buffer.
+ *     Spin if there isn't any.
+ * 2) Add the invocation and optionally the proxy containing the return value
+ * (nil for none) to the next two elements in the ring buffer.
+ * 3) Increment the producer counter (by two, since we are adding two elements).
+ * 4) If the queue was previously empty, we need to transition back to lockless
+ * mode.  This is done by signalling the condition variable that the other
+ * thread will be waiting on if it is in blocking mode.
+ */
+inline static void insert_into_queue(dispatch_queue_t queue,
+		dispatch_function_t function, 
+		void *data)
+{
+	/* Wait for space in the buffer */
+	lock_queue(queue);
+	while (ISFULL(queue))
+	{
+		sched_yield();
+	}
+	unsigned int idx = MASK(queue->producer);
+	queue->ring_buffer[idx].function = function;
+	queue->ring_buffer[idx].data = data;
+	// NOTE: This doesn't actually need to be atomic on a strongly-ordered
+	// architecture like x86.
+	__sync_fetch_and_add(&queue->producer, 1);
+	unsigned int space = queue->producer - queue->consumer;
+	unlock_queue(queue);
+	// If we've just transitioned from empty to full, wake up the consumer thread.
+	// Note: We do this after unlocking the queue, because it is much more
+	// expensive than anything else that we do in this function and we don't
+	// want to hold the spinlock for any longer than possible.  We need to
+	// calculate the space first, however, because otherwise another thread may
+	// increment producer, while consumer stays the same (with the consumer
+	// thread sleeping), preventing the wakeup.
+	if (space == 1)
+	{
+		pthread_mutex_lock(&queue->mutex);
+		pthread_cond_signal(&queue->conditionVariable);
+		pthread_mutex_unlock(&queue->mutex);
+	}
+}
+/**
+ * Removing an element from the queue involves the following steps:
+ *
+ * 1) Wait until the queue has messages waiting.  If there are none, enter
+ * blocking mode.  The additional test inside the mutex ensures that a
+ * transition from blocking to non-blocking mode will not be missed, since the
+ * condition variable can only be signalled when the producer thread has the
+ * mutex.  
+ * 2) Read the invocation and return proxy from the buffer.
+ * 3) Incrememt the consumer counter.
+ */
+static inline void read_from_queue(dispatch_queue_t queue, 
+		dispatch_function_t *function, void **data)
+{
+	while (ISEMPTY(queue))
+	{
+		pthread_mutex_lock(&queue->mutex);
+		if (ISEMPTY(queue))
+		{
+			pthread_cond_wait(&queue->conditionVariable, &queue->mutex);
+		}
+		pthread_mutex_unlock(&queue->mutex);
+	}
+	unsigned int idx = MASK(queue->consumer);
+	*function = queue->ring_buffer[idx].function;
+	*data = queue->ring_buffer[idx].data;
+	__sync_fetch_and_add(&queue->consumer, 1);
+}
+
+static void *runloop(void *q)
+{
+	dispatch_queue_t queue = q;
+	dispatch_function_t function;
+	void *data;
+	while (queue->refcount > 0)
+	{
+		read_from_queue(queue, &function, &data);
+		function(data);
+	}
+	pthread_cond_destroy(&queue->conditionVariable);
+	pthread_mutex_destroy(&queue->mutex);
+	free(queue);
+	return NULL;
+}
+
+
+dispatch_queue_t dispatch_queue_create(const char *label,
+		void *attr)
+{
+	dispatch_queue_t queue = calloc(1, sizeof(struct dispatch_queue));
+	queue->refcount = 1;
+	pthread_cond_init(&queue->conditionVariable, NULL);
+	pthread_mutex_init(&queue->mutex, NULL);
+	pthread_t thread;
+	pthread_create(&thread, NULL, runloop, queue);
+	pthread_detach(thread);
+	return queue;
+}
+
+void dispatch_async_f(dispatch_queue_t queue, void *context,
+		dispatch_function_t work)
+{
+	insert_into_queue(queue, work, context);
+}
+
+static void release(void *queue)
+{
+	((dispatch_queue_t)queue)->refcount--;
+}
+
+void dispatch_release(dispatch_queue_t queue)
+{
+	// Asynchronously release the queue, so that we don't delete it before all
+	// of the work is finished.
+	insert_into_queue(queue, release, queue);
+}
+
+void dispatch_retain(dispatch_queue_t queue)
+{
+	queue->refcount++;
+}
diff --git a/third_party/libobjc/type_encoding_cases.h b/third_party/libobjc/type_encoding_cases.h
new file mode 100644
index 0000000000000000000000000000000000000000..36ab51651b4e73abb90da07d8542d177be6ed39f
--- /dev/null
+++ b/third_party/libobjc/type_encoding_cases.h
@@ -0,0 +1,35 @@
+/** 
+ * type_encoding_cases.h -  expects the APPLY_TYPE macro to be defined.  This
+ * macro is invoked once for every type and its Objective-C name.  Use this
+ * file when implementing things like the -unsignedIntValue family of methods.
+ * For this case, the macro will be invoked with unsigned int as the type and
+ * unsignedInt as the name.
+ */
+#ifndef APPLY_TYPE
+#error Define APPLY_TYPE(type, name, capitalizedName, encodingChar) before including this file
+#endif
+APPLY_TYPE(double, double, Double, 'd')
+APPLY_TYPE(float, float, Float, 'f')
+APPLY_TYPE(signed char, char, Char, 'c')
+APPLY_TYPE(int, int, Int, 'i')
+APPLY_TYPE(short, short, Short, 's')
+APPLY_TYPE(long, long, Long, 'l')
+APPLY_TYPE(long long, longLong, LongLong, 'q')
+//APPLY_TYPE(__int128, int128, Int128, 't')
+APPLY_TYPE(unsigned char, unsignedChar, UnsignedChar, 'C')
+APPLY_TYPE(unsigned short, unsignedShort, UnsignedShort, 'S')
+APPLY_TYPE(unsigned int, unsignedInt, UnsignedInt, 'I')
+APPLY_TYPE(unsigned long, unsignedLong, UnsignedLong, 'L')
+APPLY_TYPE(unsigned long long, unsignedLongLong, UnsignedLongLong, 'Q')
+//APPLY_TYPE(unsigned __int128, unsignedInt128, UnsignedInt128, 'T')
+#ifdef NON_INTEGER_TYPES
+#undef NON_INTEGER_TYPES
+APPLY_TYPE(_Bool, bool, Bool, 'B')
+#ifndef SKIP_ID
+APPLY_TYPE(id, object, Object, '@')
+#endif
+APPLY_TYPE(Class, class, Class, '#')
+APPLY_TYPE(SEL, selector, Selector, ':')
+APPLY_TYPE(char*, cString, CString, '*')
+#endif
+#undef APPLY_TYPE
diff --git a/third_party/libobjc/unistd.h b/third_party/libobjc/unistd.h
new file mode 100644
index 0000000000000000000000000000000000000000..f0ce70d66bc68ffbe0b4a810590c680c5276d2ef
--- /dev/null
+++ b/third_party/libobjc/unistd.h
@@ -0,0 +1,8 @@
+/* See http://llvm.org/bugs/show_bug.cgi?id=4746 */
+#ifdef __block
+#	undef __block
+#	include_next "unistd.h"
+#	define __block __attribute__((__blocks__(byref)))
+#else
+#	include_next "unistd.h"
+#endif
diff --git a/third_party/libobjc/unwind-arm.h b/third_party/libobjc/unwind-arm.h
new file mode 100644
index 0000000000000000000000000000000000000000..63774611ca185fc938a07480e7e4ee8dc4633942
--- /dev/null
+++ b/third_party/libobjc/unwind-arm.h
@@ -0,0 +1,195 @@
+/**
+ * ARM-specific unwind definitions.  These are taken from the ARM EHABI
+ * specification.
+ */
+ typedef enum
+{
+	_URC_OK = 0,                /* operation completed successfully */
+	_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+    _URC_END_OF_STACK = 5,
+	_URC_HANDLER_FOUND = 6,
+	_URC_INSTALL_CONTEXT = 7,
+	_URC_CONTINUE_UNWIND = 8,
+	_URC_FAILURE = 9,            /* unspecified failure of some kind */
+	_URC_FATAL_PHASE1_ERROR = _URC_FAILURE
+} _Unwind_Reason_Code;
+
+typedef uint32_t _Unwind_State;
+#ifdef __clang__
+static const _Unwind_State _US_VIRTUAL_UNWIND_FRAME  = 0;
+static const _Unwind_State _US_UNWIND_FRAME_STARTING = 1;
+static const _Unwind_State _US_UNWIND_FRAME_RESUME   = 2;
+#else // GCC fails at knowing what a constant expression is
+#	define _US_VIRTUAL_UNWIND_FRAME  0
+#	define _US_UNWIND_FRAME_STARTING 1
+#	define _US_UNWIND_FRAME_RESUME 2
+#endif
+
+typedef struct _Unwind_Context _Unwind_Context;
+
+typedef uint32_t _Unwind_EHT_Header;
+
+struct _Unwind_Exception
+{
+	uint64_t exception_class;
+	void (*exception_cleanup)(_Unwind_Reason_Code, struct _Unwind_Exception *);
+	/* Unwinder cache, private fields for the unwinder's use */
+	struct
+	{
+		uint32_t reserved1;
+		uint32_t reserved2;
+		uint32_t reserved3;
+		uint32_t reserved4;
+		uint32_t reserved5;
+	/* init reserved1 to 0, then don't touch */
+	} unwinder_cache;
+	/* Propagation barrier cache (valid after phase 1): */
+	struct
+	{
+		uint32_t sp;
+		uint32_t bitpattern[5];
+	} barrier_cache;
+	/* Cleanup cache (preserved over cleanup): */
+	struct
+	{
+		uint32_t bitpattern[4];
+	} cleanup_cache;
+	/* Pr cache (for pr's benefit): */
+	struct
+	{
+		/** function start address */
+		uint32_t fnstart;
+		/** pointer to EHT entry header word */
+		_Unwind_EHT_Header *ehtp;
+		/** additional data */
+		uint32_t additional;
+		uint32_t reserved1;
+	} pr_cache;
+	/** Force alignment of next item to 8-byte boundary */
+	long long int :0;
+};
+
+/* Unwinding functions */
+_Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception *ucbp);
+void _Unwind_Resume(struct _Unwind_Exception *ucbp);
+void _Unwind_Complete(struct _Unwind_Exception *ucbp);
+void _Unwind_DeleteException(struct _Unwind_Exception *ucbp);
+void *_Unwind_GetLanguageSpecificData(struct _Unwind_Context*);
+
+typedef enum
+{
+	_UVRSR_OK = 0,
+	_UVRSR_NOT_IMPLEMENTED = 1,
+	_UVRSR_FAILED = 2
+} _Unwind_VRS_Result;
+typedef enum
+{
+	_UVRSC_CORE = 0,
+	_UVRSC_VFP = 1,
+	_UVRSC_WMMXD = 3,
+	_UVRSC_WMMXC = 4
+} _Unwind_VRS_RegClass;
+typedef enum
+{
+	_UVRSD_UINT32 = 0,
+	_UVRSD_VFPX = 1,
+	_UVRSD_UINT64 = 3,
+	_UVRSD_FLOAT = 4,
+	_UVRSD_DOUBLE = 5
+} _Unwind_VRS_DataRepresentation;
+
+_Unwind_VRS_Result _Unwind_VRS_Get(_Unwind_Context *context,
+                                   _Unwind_VRS_RegClass regclass,
+                                   uint32_t regno,
+                                   _Unwind_VRS_DataRepresentation representation,
+                                   void *valuep);
+_Unwind_VRS_Result _Unwind_VRS_Set(_Unwind_Context *context,
+                                   _Unwind_VRS_RegClass regclass,
+                                   uint32_t regno,
+                                   _Unwind_VRS_DataRepresentation representation,
+                                   void *valuep);
+
+/* Return the base-address for data references.  */
+extern unsigned long _Unwind_GetDataRelBase(struct _Unwind_Context *);
+
+/* Return the base-address for text references.  */
+extern unsigned long _Unwind_GetTextRelBase(struct _Unwind_Context *);
+extern unsigned long _Unwind_GetRegionStart(struct _Unwind_Context *);
+
+/**
+ * The next set of functions are compatibility extensions, implementing Itanium
+ * ABI functions on top of ARM ones.
+ */
+
+#define _UA_SEARCH_PHASE	1
+#define _UA_CLEANUP_PHASE	2
+#define _UA_HANDLER_FRAME	4
+#define _UA_FORCE_UNWIND	8
+
+static inline unsigned long _Unwind_GetGR(struct _Unwind_Context *context, int reg)
+{
+	unsigned long val;
+	_Unwind_VRS_Get(context, _UVRSC_CORE, reg, _UVRSD_UINT32, &val);
+	return val;
+}
+static inline  void _Unwind_SetGR(struct _Unwind_Context *context, int reg, unsigned long val)
+{
+	_Unwind_VRS_Set(context, _UVRSC_CORE, reg, _UVRSD_UINT32, &val);
+}
+static inline unsigned long _Unwind_GetIP(_Unwind_Context *context)
+{
+	// Low bit store the thumb state - discard it
+	return _Unwind_GetGR(context, 15) & ~1;
+}
+static inline void _Unwind_SetIP(_Unwind_Context *context, unsigned long val)
+{
+	// The lowest bit of the instruction pointer indicates whether we're in
+	// thumb or ARM mode.  This is assumed to be fixed throughout a function,
+	// so must be propagated when setting the program counter.
+	unsigned long thumbState = _Unwind_GetGR(context, 15) & 1;
+   _Unwind_SetGR(context, 15, (val | thumbState));
+}
+
+/** GNU API function that unwinds the frame */
+_Unwind_Reason_Code __gnu_unwind_frame(struct _Unwind_Exception*, struct _Unwind_Context*);
+
+
+#define DECLARE_PERSONALITY_FUNCTION(name) \
+_Unwind_Reason_Code name(_Unwind_State state,\
+                         struct _Unwind_Exception *exceptionObject,\
+                         struct _Unwind_Context *context);
+
+#define BEGIN_PERSONALITY_FUNCTION(name) \
+_Unwind_Reason_Code name(_Unwind_State state,\
+                         struct _Unwind_Exception *exceptionObject,\
+                         struct _Unwind_Context *context)\
+{\
+	int version = 1;\
+	uint64_t exceptionClass = exceptionObject->exception_class;\
+	int actions;\
+	switch (state)\
+	{\
+		default: return _URC_FAILURE;\
+		case _US_VIRTUAL_UNWIND_FRAME:\
+		{\
+			actions = _UA_SEARCH_PHASE;\
+			break;\
+		}\
+		case _US_UNWIND_FRAME_STARTING:\
+		{\
+			actions = _UA_CLEANUP_PHASE;\
+			if (exceptionObject->barrier_cache.sp == _Unwind_GetGR(context, 13))\
+			{\
+				actions |= _UA_HANDLER_FRAME;\
+			}\
+			break;\
+		}\
+		case _US_UNWIND_FRAME_RESUME:\
+		{\
+			return continueUnwinding(exceptionObject, context);\
+			break;\
+		}\
+	}\
+	_Unwind_SetGR (context, 12, (unsigned long)exceptionObject);
+
+#define CALL_PERSONALITY_FUNCTION(name) name(state,exceptionObject,context)
diff --git a/third_party/libobjc/unwind-itanium.h b/third_party/libobjc/unwind-itanium.h
new file mode 100644
index 0000000000000000000000000000000000000000..16b3eed6d700e094b3eb7b9896f075c8baeac274
--- /dev/null
+++ b/third_party/libobjc/unwind-itanium.h
@@ -0,0 +1,170 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2003 Hewlett-Packard Co
+	Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#ifndef _UNWIND_H
+#define _UNWIND_H
+
+/* For uint64_t */
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Minimal interface as per C++ ABI draft standard:
+
+	http://www.codesourcery.com/cxx-abi/abi-eh.html */
+
+typedef enum
+  {
+    _URC_NO_REASON = 0,
+    _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+    _URC_FATAL_PHASE2_ERROR = 2,
+    _URC_FATAL_PHASE1_ERROR = 3,
+    _URC_NORMAL_STOP = 4,
+    _URC_END_OF_STACK = 5,
+    _URC_HANDLER_FOUND = 6,
+    _URC_INSTALL_CONTEXT = 7,
+    _URC_CONTINUE_UNWIND = 8
+  }
+_Unwind_Reason_Code;
+
+typedef int _Unwind_Action;
+
+#define _UA_SEARCH_PHASE	1
+#define _UA_CLEANUP_PHASE	2
+#define _UA_HANDLER_FRAME	4
+#define _UA_FORCE_UNWIND	8
+
+struct _Unwind_Context;		/* opaque data-structure */
+struct _Unwind_Exception;	/* forward-declaration */
+
+typedef void (*_Unwind_Exception_Cleanup_Fn) (_Unwind_Reason_Code,
+					      struct _Unwind_Exception *);
+
+typedef _Unwind_Reason_Code (*_Unwind_Stop_Fn) (int, _Unwind_Action,
+						uint64_t,
+						struct _Unwind_Exception *,
+						struct _Unwind_Context *,
+						void *);
+
+/* The C++ ABI requires exception_class, private_1, and private_2 to
+   be of type uint64 and the entire structure to be
+   double-word-aligned. Please note that exception_class stays 64-bit 
+   even on 32-bit machines for gcc compatibility.  */
+struct _Unwind_Exception
+  {
+    uint64_t exception_class;
+    _Unwind_Exception_Cleanup_Fn exception_cleanup;
+    unsigned long private_1;
+    unsigned long private_2;
+  } __attribute__((__aligned__));
+
+extern _Unwind_Reason_Code _Unwind_RaiseException (struct _Unwind_Exception *);
+extern _Unwind_Reason_Code _Unwind_ForcedUnwind (struct _Unwind_Exception *,
+						 _Unwind_Stop_Fn, void *);
+extern void _Unwind_Resume (struct _Unwind_Exception *);
+extern void _Unwind_DeleteException (struct _Unwind_Exception *);
+extern unsigned long _Unwind_GetGR (struct _Unwind_Context *, int);
+extern void _Unwind_SetGR (struct _Unwind_Context *, int, unsigned long);
+extern unsigned long _Unwind_GetIP (struct _Unwind_Context *);
+extern unsigned long _Unwind_GetIPInfo (struct _Unwind_Context *, int *);
+extern void _Unwind_SetIP (struct _Unwind_Context *, unsigned long);
+extern unsigned long _Unwind_GetLanguageSpecificData (struct _Unwind_Context*);
+extern unsigned long _Unwind_GetRegionStart (struct _Unwind_Context *);
+
+#ifdef _GNU_SOURCE
+
+/* Callback for _Unwind_Backtrace().  The backtrace stops immediately
+   if the callback returns any value other than _URC_NO_REASON. */
+typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn) (struct _Unwind_Context *,
+						 void *);
+
+/* See http://gcc.gnu.org/ml/gcc-patches/2001-09/msg00082.html for why
+   _UA_END_OF_STACK exists.  */
+# define _UA_END_OF_STACK	16
+
+/* If the unwind was initiated due to a forced unwind, resume that
+   operation, else re-raise the exception.  This is used by
+   __cxa_rethrow().  */
+extern _Unwind_Reason_Code
+	  _Unwind_Resume_or_Rethrow (struct _Unwind_Exception *);
+
+/* See http://gcc.gnu.org/ml/gcc-patches/2003-09/msg00154.html for why
+   _Unwind_GetBSP() exists.  */
+extern unsigned long _Unwind_GetBSP (struct _Unwind_Context *);
+
+/* Return the "canonical frame address" for the given context.
+   This is used by NPTL... */
+extern unsigned long _Unwind_GetCFA (struct _Unwind_Context *);
+
+/* Return the base-address for data references.  */
+extern unsigned long _Unwind_GetDataRelBase (struct _Unwind_Context *);
+
+/* Return the base-address for text references.  */
+extern unsigned long _Unwind_GetTextRelBase (struct _Unwind_Context *);
+
+/* Call _Unwind_Trace_Fn once for each stack-frame, without doing any
+   cleanup.  The first frame for which the callback is invoked is the
+   one for the caller of _Unwind_Backtrace().  _Unwind_Backtrace()
+   returns _URC_END_OF_STACK when the backtrace stopped due to
+   reaching the end of the call-chain or _URC_FATAL_PHASE1_ERROR if it
+   stops for any other reason.  */
+extern _Unwind_Reason_Code _Unwind_Backtrace (_Unwind_Trace_Fn, void *);
+
+/* Find the start-address of the procedure containing the specified IP
+   or NULL if it cannot be found (e.g., because the function has no
+   unwind info).  Note: there is not necessarily a one-to-one
+   correspondence between source-level functions and procedures: some
+   functions don't have unwind-info and others are split into multiple
+   procedures.  */
+extern void *_Unwind_FindEnclosingFunction (void *);
+
+/* See also Linux Standard Base Spec:
+    http://www.linuxbase.org/spec/refspecs/LSB_1.3.0/gLSB/gLSB/libgcc-s.html */
+
+#endif /* _GNU_SOURCE */
+
+#define DECLARE_PERSONALITY_FUNCTION(name) \
+_Unwind_Reason_Code name(int version,\
+                         _Unwind_Action actions,\
+                         uint64_t exceptionClass,\
+                         struct _Unwind_Exception *exceptionObject,\
+                         struct _Unwind_Context *context);
+#define BEGIN_PERSONALITY_FUNCTION(name) \
+_Unwind_Reason_Code name(int version,\
+                         _Unwind_Action actions,\
+                         uint64_t exceptionClass,\
+                         struct _Unwind_Exception *exceptionObject,\
+                         struct _Unwind_Context *context)\
+{
+
+#define CALL_PERSONALITY_FUNCTION(name) name(version, actions, exceptionClass, exceptionObject, context)
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UNWIND_H */
diff --git a/third_party/libobjc/unwind.h b/third_party/libobjc/unwind.h
new file mode 100644
index 0000000000000000000000000000000000000000..76b678048517d19c6ffdd1a41ca37eb5ba2a732c
--- /dev/null
+++ b/third_party/libobjc/unwind.h
@@ -0,0 +1,5 @@
+#ifdef __arm__
+#include "unwind-arm.h"
+#else
+#include "unwind-itanium.h"
+#endif
diff --git a/third_party/libobjc/visibility.h b/third_party/libobjc/visibility.h
new file mode 100644
index 0000000000000000000000000000000000000000..86c379b0001b94026b4a6c6475461862469fcfcd
--- /dev/null
+++ b/third_party/libobjc/visibility.h
@@ -0,0 +1,24 @@
+#if defined _WIN32 || defined __CYGWIN__
+#	define PUBLIC __attribute__((dllexport))
+#	define PRIVATE
+#else
+#	define PUBLIC __attribute__ ((visibility("default")))
+#	define PRIVATE  __attribute__ ((visibility("hidden")))
+#endif
+#ifdef NO_LEGACY
+#	define LEGACY PRIVATE
+#else
+#	define LEGACY PUBLIC
+#endif
+
+#if defined(DEBUG) || (!defined(__clang__))
+#	include <assert.h>
+#	define UNREACHABLE(x) assert(0 && x)
+#	define ASSERT(x) assert(x)
+#else
+#	define UNREACHABLE(x) __builtin_unreachable()
+#	define ASSERT(x) do { if (x) __builtin_unreachable(); } while(0)
+#endif
+
+#define LIKELY(x) __builtin_expect(x, 1)
+#define UNLIKELY(x) __builtin_expect(x, 0)