From 3428d21d55eee9b31b10ed4e2c999844466eb92d Mon Sep 17 00:00:00 2001
From: Konstantin Osipov <kostja@tarantool.org>
Date: Thu, 14 Mar 2013 21:46:16 +0400
Subject: [PATCH] Import the new libobjc runtime from the trunk.

Preserve the zero-warnings patch.
---
 third_party/README                            |   4 +-
 third_party/libobjc/ANNOUNCE                  |  46 ++-
 third_party/libobjc/ANNOUNCE.1.6.1            |  41 ++
 third_party/libobjc/Makefile                  |  26 +-
 third_party/libobjc/Test/BlockImpTest.m       |  54 ---
 third_party/libobjc/Test/GNUmakefile          |   8 -
 .../libobjc/Test/PropertyIntrospectionTest.m  |  36 --
 third_party/libobjc/Test/ProtocolCreation.m   |  28 --
 third_party/libobjc/Test/RuntimeTest.m        | 298 --------------
 .../RuntimeTest.xcodeproj/project.pbxproj     | 203 ----------
 third_party/libobjc/Test/objc_msgSend.m       | 143 -------
 third_party/libobjc/arc.m                     |  19 +-
 third_party/libobjc/class_table.c             |   5 +-
 third_party/libobjc/dtable.c                  |  52 ++-
 third_party/libobjc/dwarf_eh.h                |   4 +-
 third_party/libobjc/eh_personality.c          | 367 ++++++++++++++++--
 third_party/libobjc/encoding2.c               |  26 +-
 third_party/libobjc/hash_table.h              |   1 +
 third_party/libobjc/loader.c                  |  11 +
 third_party/libobjc/lock.h                    |   2 +-
 third_party/libobjc/objc/Availability.h       |   4 +
 third_party/libobjc/objc/Object.h             |   4 +
 third_party/libobjc/objc/Protocol.h           |   4 +
 third_party/libobjc/objc/blocks_private.h     |   4 +
 third_party/libobjc/objc/blocks_runtime.h     |   4 +
 third_party/libobjc/objc/capabilities.h       |   4 +
 third_party/libobjc/objc/developer.h          |   4 +
 third_party/libobjc/objc/encoding.h           |   4 +
 third_party/libobjc/objc/hooks.h              |   4 +
 third_party/libobjc/objc/message.h            |  62 +++
 third_party/libobjc/objc/objc-api.h           |   4 +
 third_party/libobjc/objc/objc-arc.h           |   4 +
 third_party/libobjc/objc/objc-auto.h          |   4 +
 third_party/libobjc/objc/runtime-deprecated.h |   4 +
 third_party/libobjc/objc/runtime.h            |   6 +
 third_party/libobjc/objc/slot.h               |   4 +
 third_party/libobjc/objc_msgSend.x86-32.S     |  11 +-
 third_party/libobjc/objc_msgSend.x86-64.S     |   2 +-
 third_party/libobjc/objcxx_eh.cc              |   8 +-
 third_party/libobjc/objcxx_eh.h               |   6 +-
 third_party/libobjc/opts/CMakeLists.txt       |  37 +-
 third_party/libobjc/opts/ClassIMPCache.cpp    |   8 -
 third_party/libobjc/opts/ClassLookupCache.cpp |  12 +-
 .../libobjc/opts/ClassMethodInliner.cpp       |   9 -
 third_party/libobjc/opts/IMPCacher.cpp        |   8 -
 third_party/libobjc/opts/IvarPass.cpp         |  10 +-
 third_party/libobjc/opts/LLVMCompat.h         |  30 +-
 third_party/libobjc/opts/LoopIMPCachePass.cpp |   9 +-
 third_party/libobjc/opts/ObjectiveCOpts.cpp   |   7 +-
 third_party/libobjc/opts/TypeFeedback.cpp     |  17 +-
 .../opts/TypeFeedbackDrivenInliner.cpp        |   7 +-
 third_party/libobjc/opts/TypeInfoProvider.h   |   9 +-
 third_party/libobjc/pool.h                    |   4 +
 third_party/libobjc/properties.h              |  69 +++-
 third_party/libobjc/properties.m              | 317 ++++++++++++---
 third_party/libobjc/protocol.c                |  45 +--
 third_party/libobjc/runtime.c                 |   9 +-
 third_party/libobjc/sarray2.c                 |  98 ++++-
 third_party/libobjc/sarray2.h                 |   7 +-
 third_party/libobjc/selector_table.c          |  60 ++-
 third_party/libobjc/spinlock.h                |   2 +-
 third_party/libobjc/unwind-arm.h              |   2 +
 62 files changed, 1217 insertions(+), 1084 deletions(-)
 create mode 100644 third_party/libobjc/ANNOUNCE.1.6.1
 delete mode 100644 third_party/libobjc/Test/BlockImpTest.m
 delete mode 100644 third_party/libobjc/Test/GNUmakefile
 delete mode 100644 third_party/libobjc/Test/PropertyIntrospectionTest.m
 delete mode 100644 third_party/libobjc/Test/ProtocolCreation.m
 delete mode 100644 third_party/libobjc/Test/RuntimeTest.m
 delete mode 100644 third_party/libobjc/Test/RuntimeTest.xcodeproj/project.pbxproj
 delete mode 100644 third_party/libobjc/Test/objc_msgSend.m
 create mode 100644 third_party/libobjc/objc/message.h

diff --git a/third_party/README b/third_party/README
index 67c19db348..33ce150b1e 100644
--- a/third_party/README
+++ b/third_party/README
@@ -30,6 +30,8 @@ rm GNUMakefile
 
 How to update it:
 
-- delete GNUMakefile
+- delete GNUmakefile
+- delete CMakeLists.txt
 - merge our Makefile with the Makefile in
 the source tarball
+- preserve the zero-warnings patch 43771c84f7f5bf04e426dde30a31303d4699f00d
diff --git a/third_party/libobjc/ANNOUNCE b/third_party/libobjc/ANNOUNCE
index 75950a35df..c7b31ab7b2 100644
--- a/third_party/libobjc/ANNOUNCE
+++ b/third_party/libobjc/ANNOUNCE
@@ -1,27 +1,47 @@
-GNUstep Objective-C Runtime 1.6.1
+GNUstep Objective-C Runtime 1.7
 ===============================
 
-This is a point release to the seventh official release of the GNUstep
+This is a point release to the eighth 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:
+the features of modern dialects of Objective-C for use with GNUstep and other
+Objective-C programs.  Highlights of this release include:
 
-- Improved support for ARC autorelease pools.
+- A new CMake-based build system.  This makes all of the configurable options
+  available via a clean interface.  CPack is supported for building RPM and DEB
+  packages out of the box.
 
-- Some small bug fixes in blocks support.
+- A new CTest-based test suite, replacing the old ad-hoc tests.
 
-- Improvements to the Objective-C++ unified exception model support.
+- Build a single libobjc with support for Objective-C++ on platforms where a
+  C++ ABI library (libcxxrt or libsupc++) is installed as a shared library.
+
+- Added specialised property accessor functions and support for atomic
+  properties with C++ non-POD types.
+
+- Significant improvements in property introspection and an exhaustive test
+  suite.
+
+- A new exception implementation providing better integration with foreign
+  exceptions (e.g. C++ exceptions).  The new ABI is supported by clang 3.3 when
+  compiling with -fobjc-runtime=gnustep-1.7 (or higher).  The old ABI is still
+  supported and both can be used within the same program, however code compiled
+  with the old ABI remains unreliable in the presence of foreign exceptions.
+  It is strongly recommended that anyone using exceptions with Objective-C++
+  switches to the new version.
+
+- MIPS64 support in the assembly routines. (TODO)
+
+- Updated optimisation passes to work with LLVM 3.2 and recent LLVM trunk.
 
-- 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
+svn://svn.gna.org/svn/gnustep/libs/libobjc2/1.7
 
 Alternatively, a tarball is available from:
 
-http://download.gna.org/gnustep/libobjc2-1.6.1.tar.bz2
+http://download.gna.org/gnustep/libobjc2-1.7.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
@@ -35,7 +55,5 @@ 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>.  
+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.1 b/third_party/libobjc/ANNOUNCE.1.6.1
new file mode 100644
index 0000000000..03f6ba0ca2
--- /dev/null
+++ b/third_party/libobjc/ANNOUNCE.1.6.1
@@ -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/Makefile b/third_party/libobjc/Makefile
index dbe0adbdc3..45bc5634d7 100644
--- a/third_party/libobjc/Makefile
+++ b/third_party/libobjc/Makefile
@@ -5,27 +5,33 @@
 MAJOR_VERSION = 4
 MINOR_VERSION = 6
 SUBMINOR_VERSION = 0
-VERSION = $(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION)
+VERSION ?= $(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION)
 
 LIBOBJCLIBNAME=objc
 LIBOBJC=libobjc
 LIBOBJCXX=libobjcxx
 
-#SILENT=@
+INSTALL ?= install
+#SILENT ?= @
 
-CFLAGS+= -std=gnu99 -fexceptions
-CXXFLAGS+= -fexceptions
-CPPFLAGS+= -DTYPE_DEPENDENT_DISPATCH -DGNUSTEP
-CPPFLAGS+= -D__OBJC_RUNTIME_INTERNAL__=1 -D_XOPEN_SOURCE=500 -D__BSD_VISIBLE=1 -D_BSD_SOURCE=1
+CFLAGS += -std=gnu99 -fexceptions
+#CFLAGS += -Wno-deprecated-objc-isa-usage
+CXXFLAGS += -fexceptions
+CPPFLAGS += -DTYPE_DEPENDENT_DISPATCH -DGNUSTEP
+CPPFLAGS += -D__OBJC_RUNTIME_INTERNAL__=1 -D_XOPEN_SOURCE=500 -D__BSD_VISIBLE=1 -D_BSD_SOURCE=1
 
 ASMFLAGS += `if $(CC) -v 2>&1| grep -q 'clang' ; then echo -no-integrated-as ; fi`
 
+THE_LD=`if [ "$(LD)" = "" ]; then echo "ld"; else echo "$(LD)"; fi` 
+
 STRIP=`if [ "$(strip)" = "yes" ] ; then echo -s ; fi`
 
 # Suppress warnings about incorrect selectors
 CPPFLAGS += -DNO_SELECTOR_MISMATCH_WARNINGS
 # Some helpful flags for debugging.
 CPPFLAGS+= ${EXTRA_CFLAGS}
+##CPPFLAGS += -g -O0 -fno-inline
+#CPPFLAGS += -O3
 
 PREFIX?= /usr/local
 LIB_DIR= ${PREFIX}/lib
@@ -72,18 +78,18 @@ all: $(LIBOBJC).a
 $(LIBOBJCXX).so.$(VERSION): $(LIBOBJC).so.$(VERSION) $(OBJCXX_OBJECTS)
 	$(SILENT)echo Linking shared Objective-C++ runtime library...
 	$(SILENT)$(CXX) -shared \
-            -Wl,-soname=$(LIBOBJCXX).so.$(MAJOR_VERSION) \
+            -Wl,-soname=$(LIBOBJCXX).so.$(MAJOR_VERSION) $(LDFLAGS) \
             -o $@ $(OBJCXX_OBJECTS)
 
 $(LIBOBJC).so.$(VERSION): $(OBJECTS)
 	$(SILENT)echo Linking shared Objective-C runtime library...
 	$(SILENT)$(CC) -shared -rdynamic \
-            -Wl,-soname=$(LIBOBJC).so.$(MAJOR_VERSION) \
+            -Wl,-soname=$(LIBOBJC).so.$(MAJOR_VERSION) $(LDFLAGS) \
             -o $@ $(OBJECTS)
 
 $(LIBOBJC).a: $(OBJECTS)
 	$(SILENT)echo Linking static Objective-C runtime library...
-	$(SILENT)ld -r ${EXTRA_LDFLAGS} -o $@ $(OBJECTS)
+	$(SILENT)$(THE_LD) -r -s -o $@ $(OBJECTS)
 
 .cc.o: Makefile
 	$(SILENT)echo Compiling `basename $<`...
@@ -101,7 +107,7 @@ $(LIBOBJC).a: $(OBJECTS)
 	$(SILENT)echo Assembling `basename $<`...
 	$(SILENT)$(CC) $(CPPFLAGS) $(ASMFLAGS) -c $< -o $@
 
-install: all
+$(INSTALL): all
 	$(SILENT)echo Installing libraries...
 	$(SILENT)install -d $(LIB_DIR)
 	$(SILENT)install -m 444 $(STRIP) $(LIBOBJC).so.$(VERSION) $(LIB_DIR)
diff --git a/third_party/libobjc/Test/BlockImpTest.m b/third_party/libobjc/Test/BlockImpTest.m
deleted file mode 100644
index f43a040f38..0000000000
--- a/third_party/libobjc/Test/BlockImpTest.m
+++ /dev/null
@@ -1,54 +0,0 @@
-#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
deleted file mode 100644
index 94e24fdc15..0000000000
--- a/third_party/libobjc/Test/GNUmakefile
+++ /dev/null
@@ -1,8 +0,0 @@
-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
deleted file mode 100644
index bcf82b7446..0000000000
--- a/third_party/libobjc/Test/PropertyIntrospectionTest.m
+++ /dev/null
@@ -1,36 +0,0 @@
-#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
deleted file mode 100644
index 204021d88f..0000000000
--- a/third_party/libobjc/Test/ProtocolCreation.m
+++ /dev/null
@@ -1,28 +0,0 @@
-#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
deleted file mode 100644
index 83eeb05b3b..0000000000
--- a/third_party/libobjc/Test/RuntimeTest.m
+++ /dev/null
@@ -1,298 +0,0 @@
-#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
deleted file mode 100644
index 29fc106662..0000000000
--- a/third_party/libobjc/Test/RuntimeTest.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,203 +0,0 @@
-// !$*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
deleted file mode 100644
index ff179cda9c..0000000000
--- a/third_party/libobjc/Test/objc_msgSend.m
+++ /dev/null
@@ -1,143 +0,0 @@
-#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/arc.m b/third_party/libobjc/arc.m
index 6bc56b6645..483cd5132c 100644
--- a/third_party/libobjc/arc.m
+++ b/third_party/libobjc/arc.m
@@ -17,6 +17,7 @@ pthread_key_t ARCThreadKey;
 #endif
 
 extern char _NSConcreteMallocBlock;
+extern char _NSConcreteStackBlock;
 extern char _NSConcreteGlobalBlock;
 
 @interface NSAutoreleasePool
@@ -133,13 +134,12 @@ static void emptyPool(struct arc_tls *tls, id *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)
+	if (NULL != tls->pool)
 	{
 		emptyPool(tls, NULL);
 		assert(NULL == tls->pool);
@@ -167,7 +167,8 @@ static inline id retain(id obj)
 {
 	if (isSmallObject(obj)) { return obj; }
 	Class cls = obj->isa;
-	if ((Class)&_NSConcreteMallocBlock == cls)
+	if ((Class)&_NSConcreteMallocBlock == cls ||
+	    (Class)&_NSConcreteStackBlock == cls)
 	{
 		return Block_copy(obj);
 	}
@@ -184,6 +185,16 @@ static inline void release(id obj)
 {
 	if (isSmallObject(obj)) { return; }
 	Class cls = obj->isa;
+	if (cls == (Class)&_NSConcreteMallocBlock)
+	{
+		_Block_release(obj);
+		return;
+	}
+	if ((cls == (Class)&_NSConcreteStackBlock) ||
+	    (cls == (Class)&_NSConcreteGlobalBlock))
+	{
+		return;
+	}
 	if (objc_test_class_flag(cls, objc_class_flag_fast_arc))
 	{
 		intptr_t *refCount = ((intptr_t*)obj) - 1;
@@ -519,7 +530,7 @@ id objc_storeWeak(id *addr, id obj)
 					break;
 				}
 			}
-			oldRef = oldRef->next;
+			oldRef = (oldRef == NULL) ? NULL : oldRef->next;
 		}
 	}
 	if (nil == obj)
diff --git a/third_party/libobjc/class_table.c b/third_party/libobjc/class_table.c
index 8feb1f4890..fa9a876c78 100644
--- a/third_party/libobjc/class_table.c
+++ b/third_party/libobjc/class_table.c
@@ -244,7 +244,10 @@ PRIVATE BOOL objc_resolve_class(Class cls)
 	// Fix up the ivar offsets
 	objc_compute_ivar_offsets(cls);
 	// Send the +load message, if required
-	objc_send_load_message(cls);
+	if (!objc_test_class_flag(cls, objc_class_flag_user_created))
+	{
+		objc_send_load_message(cls);
+	}
 	if (_objc_load_callback)
 	{
 		_objc_load_callback(cls, 0);
diff --git a/third_party/libobjc/dtable.c b/third_party/libobjc/dtable.c
index a223511887..f534b17c9f 100644
--- a/third_party/libobjc/dtable.c
+++ b/third_party/libobjc/dtable.c
@@ -18,7 +18,8 @@ PRIVATE dtable_t uninstalled_dtable;
 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. */
+/** The size of the largest dtable.  This is a sparse array shift value, so is
+ * 2^x in increments of 8. */
 static uint32_t dtable_depth = 8;
 
 struct objc_slot* objc_get_slot(Class cls, SEL selector);
@@ -555,11 +556,13 @@ PRIVATE void objc_resize_dtables(uint32_t newSize)
 
 	LOCK_RUNTIME_FOR_SCOPE();
 
-	dtable_depth <<= 1;
+	if (1<<dtable_depth > newSize) { return; }
+
+	dtable_depth += 8;
 
 	uint32_t oldMask = uninstalled_dtable->mask;
 
-	SparseArrayExpandingArray(uninstalled_dtable);
+	SparseArrayExpandingArray(uninstalled_dtable, dtable_depth);
 	// Resize all existing dtables
 	void *e = NULL;
 	struct objc_class *next;
@@ -569,7 +572,8 @@ PRIVATE void objc_resize_dtables(uint32_t newSize)
 			NULL != next->dtable &&
 			((SparseArray*)next->dtable)->mask == oldMask)
 		{
-			SparseArrayExpandingArray((void*)next->dtable);
+			SparseArrayExpandingArray((void*)next->dtable, dtable_depth);
+			SparseArrayExpandingArray((void*)next->isa->dtable, dtable_depth);
 		}
 	}
 }
@@ -666,14 +670,11 @@ PRIVATE void objc_send_initialize(id object)
 		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
@@ -683,7 +684,20 @@ PRIVATE void objc_send_initialize(id object)
 		return;
 	}
 
+	// Lock the runtime while we're creating dtables and before we acquire any
+	// other locks.  This prevents a lock-order reversal when 
+	// dtable_for_class is called from something holding the runtime lock while
+	// we're still holding the initialize lock.  We should ensure that we never
+	// acquire the runtime lock after acquiring the initialize lock.
+	LOCK_RUNTIME();
 	LOCK_OBJECT_FOR_SCOPE((id)meta);
+	LOCK(&initialize_lock);
+	if (objc_test_class_flag(class, objc_class_flag_initialized))
+	{
+		UNLOCK(&initialize_lock);
+		return;
+	}
+	BOOL skipMeta = objc_test_class_flag(meta, objc_class_flag_initialized);
 
 	// Set the initialized flag on both this class and its metaclass, to make
 	// sure that +initialize is only ever sent once.
@@ -691,7 +705,15 @@ PRIVATE void objc_send_initialize(id object)
 	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);
+	dtable_t dtable = skipMeta ? 0 : create_dtable_for_class(meta, class_dtable);
+	// Now we've finished doing things that may acquire the runtime lock, so we
+	// can hold onto the initialise lock to make anything doing
+	// dtable_for_class block until we've finished updating temporary dtable
+	// lists.
+	// If another thread holds the runtime lock, it can now proceed until it
+	// gets into a dtable_for_class call, and then block there waiting for us
+	// to finish setting up the temporary dtable.
+	UNLOCK_RUNTIME();
 
 	static SEL initializeSel = 0;
 	if (0 == initializeSel)
@@ -699,14 +721,17 @@ PRIVATE void objc_send_initialize(id object)
 		initializeSel = sel_registerName("initialize");
 	}
 
-	struct objc_slot *initializeSlot = 
-		objc_dtable_lookup(dtable, initializeSel->index);
+	struct objc_slot *initializeSlot = skipMeta ? 0 :
+			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;
+		if (!skipMeta)
+		{
+			meta->dtable = dtable;
+		}
 		class->dtable = class_dtable;
 		checkARCAccessors(class);
 		UNLOCK(&initialize_lock);
@@ -723,7 +748,12 @@ PRIVATE void objc_send_initialize(id object)
 	__attribute__((cleanup(remove_dtable)))
 	InitializingDtable meta_buffer = { meta, dtable, &buffer };
 	temporary_dtables = &meta_buffer;
+	// We now release the initialize lock.  We'll reacquire it later when we do
+	// the cleanup, but at this point we allow other threads to get the
+	// temporary dtable and call +initialize in other threads.
 	UNLOCK(&initialize_lock);
+	// We still hold the class lock at this point.  dtable_for_class will block
+	// there after acquiring the temporary dtable.
 
 	checkARCAccessors(class);
 
diff --git a/third_party/libobjc/dwarf_eh.h b/third_party/libobjc/dwarf_eh.h
index 6dbe1e6d83..56cb280152 100644
--- a/third_party/libobjc/dwarf_eh.h
+++ b/third_party/libobjc/dwarf_eh.h
@@ -284,7 +284,7 @@ __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};
+	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)
@@ -320,4 +320,4 @@ static struct dwarf_eh_action
 	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))
+#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
index 77feb2a271..b12d8b9df5 100644
--- a/third_party/libobjc/eh_personality.c
+++ b/third_party/libobjc/eh_personality.c
@@ -7,7 +7,23 @@
 #include "class.h"
 #include "objcxx_eh.h"
 
-#define fprintf(...)
+#ifndef NO_PTHREADS
+#include <pthread.h>
+#endif
+
+#ifndef DEBUG_EXCEPTIONS
+#define DEBUG_LOG(...)
+#else
+#define DEBUG_LOG(str, ...) fprintf(stderr, str, ## __VA_ARGS__)
+#endif
+
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
+#if !__has_builtin(__builtin_unreachable)
+#define __builtin_unreachable abort
+#endif
+
 
 /**
  * Class of exceptions to distinguish between this and other exception types.
@@ -26,7 +42,15 @@ struct objc_exception
 	int handlerSwitchValue;
 	/** The cached landing pad for the catch handler.*/
 	void *landingPad;
-
+	/**
+	 * Next pointer for chained exceptions.  
+	 */
+	struct objc_exception *next;
+	/**
+	 * The number of nested catches that may hold this exception.  This is
+	 * negative while an exception is being rethrown.
+	 */
+	int catch_count;
 	/** The language-agnostic part of the exception header. */
 	struct _Unwind_Exception unwindHeader;
 	/** Thrown object.  This is after the unwind header so that the C++
@@ -39,6 +63,12 @@ struct objc_exception
 	struct _Unwind_Exception *cxx_exception;
 };
 
+struct objc_exception *objc_exception_from_header(struct _Unwind_Exception *ex)
+{
+	return (struct objc_exception*)((char*)ex -
+			offsetof(struct objc_exception, unwindHeader));
+}
+
 typedef enum
 {
 	handler_none,
@@ -132,14 +162,14 @@ void objc_exception_throw(id object)
 	if ((nil != object) &&
 	    (class_respondsToSelector(classForObject(object), rethrow_sel)))
 	{
-		fprintf(stderr, "Rethrowing\n");
+		DEBUG_LOG("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);
+	DEBUG_LOG("Throwing %p\n", object);
 
 	struct objc_exception *ex = calloc(1, sizeof(struct objc_exception));
 
@@ -154,7 +184,7 @@ void objc_exception_throw(id object)
 	{
 		_objc_unexpected_exception(object);
 	}
-	fprintf(stderr, "Throw returned %d\n",(int) err);
+	DEBUG_LOG("Throw returned %d\n",(int) err);
 	abort();
 }
 
@@ -175,7 +205,7 @@ static Class get_type_table_entry(struct _Unwind_Context *context,
 
 	if (0 == class_name) { return Nil; }
 
-	fprintf(stderr, "Class name: %s\n", class_name);
+	DEBUG_LOG("Class name: %s\n", class_name);
 
 	if (strcmp("@id", class_name) == 0) { return (Class)1; }
 
@@ -211,11 +241,11 @@ static handler_type check_action_record(struct _Unwind_Context *context,
 		dw_eh_ptr_t action_record_offset_base = action_record;
 		int displacement = read_sleb128(&action_record);
 		*selector = filter;
-		fprintf(stderr, "Filter: %d\n", filter);
+		DEBUG_LOG("Filter: %d\n", filter);
 		if (filter > 0)
 		{
 			Class type = get_type_table_entry(context, lsda, filter);
-			fprintf(stderr, "%p type: %d\n", type, !foreignException);
+			DEBUG_LOG("%p type: %d\n", type, !foreignException);
 			// Catchall
 			if (Nil == type)
 			{
@@ -225,7 +255,7 @@ static handler_type check_action_record(struct _Unwind_Context *context,
 			// nothing when a foreign exception is thrown
 			else if ((Class)1 == type)
 			{
-				fprintf(stderr, "Found id catch\n");
+				DEBUG_LOG("Found id catch\n");
 				if (!foreignException)
 				{
 					return handler_catchall_id;
@@ -233,7 +263,7 @@ static handler_type check_action_record(struct _Unwind_Context *context,
 			}
 			else if (!foreignException && isKindOfClass(thrown_class, type))
 			{
-				fprintf(stderr, "found handler for %s\n", type->name);
+				DEBUG_LOG("found handler for %s\n", type->name);
 				return handler_class;
 			}
 			else if (thrown_class == type)
@@ -243,14 +273,14 @@ static handler_type check_action_record(struct _Unwind_Context *context,
 		}
 		else if (filter == 0)
 		{
-			fprintf(stderr, "0 filter\n");
+			DEBUG_LOG("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"
+			DEBUG_LOG("Filter value: %d\n"
 					"Your compiler and I disagree on the correct layout of EH data.\n", 
 					filter);
 			abort();
@@ -263,10 +293,20 @@ static handler_type check_action_record(struct _Unwind_Context *context,
 }
 
 /**
- * The Objective-C exception personality function.  
+ * The Objective-C exception personality function implementation.  This is
+ * shared by the GCC-compatible and the new implementation.
+ *
+ * The key difference is that the new implementation always returns the
+ * exception object and boxes it.
  */
-BEGIN_PERSONALITY_FUNCTION(__gnu_objc_personality_v0)
-	fprintf(stderr, "Personality function called\n");
+static inline _Unwind_Reason_Code internal_objc_personality(int version,
+                                                            _Unwind_Action actions,
+                                                            uint64_t exceptionClass,
+                                                            struct _Unwind_Exception *exceptionObject,
+                                                            struct _Unwind_Context *context,
+                                                            BOOL isNew)
+{
+	DEBUG_LOG("%s personality function called %p\n", isNew ? "New" : "Old", exceptionObject);
 	
 	// 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
@@ -276,10 +316,10 @@ BEGIN_PERSONALITY_FUNCTION(__gnu_objc_personality_v0)
 		return _URC_FATAL_PHASE1_ERROR;
 	}
 	struct objc_exception *ex = 0;
-#ifndef fprintf
+#ifdef DEBUG_EXCEPTIONS
 	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]);
+	DEBUG_LOG("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
@@ -293,12 +333,13 @@ BEGIN_PERSONALITY_FUNCTION(__gnu_objc_personality_v0)
 #ifdef NO_OBJCXX
 	if (exceptionClass == cxx_exception_class)
 	{
-		id obj = objc_object_for_cxx_exception(exceptionObject);
-		if (obj != (id)-1)
+		int objcxx;
+		id obj = objc_object_for_cxx_exception(exceptionObject, &objcxx);
+		objcxxException = objcxx;
+		if (objcxxException)
 		{
 			object = obj;
-			fprintf(stderr, "ObjC++ object exception %p\n", object);
-			objcxxException = YES;
+			DEBUG_LOG("ObjC++ object exception %p\n", object);
 			// This is a foreign exception, buy for the purposes of exception
 			// matching, we pretend that it isn't.
 			foreignException = NO;
@@ -316,18 +357,16 @@ BEGIN_PERSONALITY_FUNCTION(__gnu_objc_personality_v0)
 	// language-specific exception stuff.
 	else if (!foreignException)
 	{
-		ex = (struct objc_exception*) ((char*)exceptionObject - 
-				offsetof(struct objc_exception, unwindHeader));
-
+		ex = objc_exception_from_header(exceptionObject);
 		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);
+		DEBUG_LOG("Foreign class: %p\n", thrown_class);
 	}
 	unsigned char *lsda_addr = (void*)_Unwind_GetLanguageSpecificData(context);
-	fprintf(stderr, "LSDA: %p\n", lsda_addr);
+	DEBUG_LOG("LSDA: %p\n", lsda_addr);
 
 	// No LSDA implies no landing pads - try the next frame
 	if (0 == lsda_addr) { return _URC_CONTINUE_UNWIND; }
@@ -338,12 +377,12 @@ BEGIN_PERSONALITY_FUNCTION(__gnu_objc_personality_v0)
 	
 	if (actions & _UA_SEARCH_PHASE)
 	{
-		fprintf(stderr, "Search phase...\n");
+		DEBUG_LOG("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);
-		fprintf(stderr, "handler: %d\n", handler);
+		DEBUG_LOG("handler: %d\n", handler);
 		// If there's no action record, we've only found a cleanup, so keep
 		// searching for something real
 		if (handler == handler_class ||
@@ -351,17 +390,18 @@ BEGIN_PERSONALITY_FUNCTION(__gnu_objc_personality_v0)
 			(handler == handler_catchall))
 		{
 			saveLandingPad(context, exceptionObject, ex, selector, action.landing_pad);
-			fprintf(stderr, "Found handler! %d\n", handler);
+			DEBUG_LOG("Found handler! %d\n", handler);
 			return _URC_HANDLER_FOUND;
 		}
 		return _URC_CONTINUE_UNWIND;
 	}
-	fprintf(stderr, "Phase 2: Fight!\n");
+	DEBUG_LOG("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))
 	{
+		DEBUG_LOG("Not the handler frame, looking up the cleanup again\n");
 		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.
@@ -371,20 +411,19 @@ BEGIN_PERSONALITY_FUNCTION(__gnu_objc_personality_v0)
 		}
 		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);
+		DEBUG_LOG("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);
+			DEBUG_LOG("Ignoring handler! %d\n",handler);
 			return _URC_CONTINUE_UNWIND;
 		}
-		fprintf(stderr, "Installing cleanup...\n");
+		DEBUG_LOG("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)
 	{
@@ -396,42 +435,57 @@ BEGIN_PERSONALITY_FUNCTION(__gnu_objc_personality_v0)
 		// exception, then we need to delete the exception object.
 		if (foreignException)
 		{
-			fprintf(stderr, "Doing the foreign exception thing...\n");
+			DEBUG_LOG("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);
+			if (!isNew)
+			{
+				object = boxfunction((id)thrown_class, box_sel, exceptionObject);
+				DEBUG_LOG("Boxed as %p\n", object);
+			}
 		}
-		else // ObjCXX exception
+		else if (!isNew) // ObjCXX exception
 		{
 			_Unwind_DeleteException(exceptionObject);
 		}
+		// In the new EH ABI, we call objc_begin_catch() / and
+		// objc_end_catch(), which will wrap their __cxa* versions.
 	}
 	else
 	{
 		// Restore the saved info if we saved some last time.
 		loadLandingPad(context, exceptionObject, ex, &selector, &action.landing_pad);
 		object = ex->object;
-		free(ex);
+		if (!isNew)
+		{
+			free(ex);
+		}
 	}
 
 	_Unwind_SetIP(context, (unsigned long)action.landing_pad);
 	_Unwind_SetGR(context, __builtin_eh_return_data_regno(0), 
-			(unsigned long)object);
+			(unsigned long)(isNew ? exceptionObject : object));
 	_Unwind_SetGR(context, __builtin_eh_return_data_regno(1), selector);
 
+	DEBUG_LOG("Installing context, selector %d\n", (int)selector);
 	return _URC_INSTALL_CONTEXT;
 }
 
+BEGIN_PERSONALITY_FUNCTION(__gnu_objc_personality_v0)
+	return internal_objc_personality(version, actions, exceptionClass,
+			exceptionObject, context, NO);
+}
+BEGIN_PERSONALITY_FUNCTION(__gnustep_objc_personality_v0)
+	return internal_objc_personality(version, actions, exceptionClass,
+			exceptionObject, context, YES);
+}
 // 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));
+		struct objc_exception *ex = objc_exception_from_header(exceptionObject);
 		if (0 == ex->cxx_exception)
 		{
 			id *newEx = __cxa_allocate_exception(sizeof(id));
@@ -448,3 +502,230 @@ BEGIN_PERSONALITY_FUNCTION(__gnustep_objcxx_personality_v0)
 	return CALL_PERSONALITY_FUNCTION(__gxx_personality_v0);
 }
 #endif
+
+// Weak references to C++ runtime functions.  We don't bother testing that
+// these are 0 before calling them, because if they are not resolved then we
+// should not be in a code path that involves a C++ exception.
+__attribute__((weak)) void *__cxa_begin_catch(void *e);
+__attribute__((weak)) void __cxa_end_catch(void);
+__attribute__((weak)) void __cxa_rethrow(void);
+
+enum exception_type
+{
+	NONE,
+	CXX,
+	OBJC,
+	FOREIGN,
+	BOXED_FOREIGN
+};
+struct thread_data
+{
+	enum exception_type current_exception_type;
+	struct objc_exception *caughtExceptions;
+};
+
+// IF we don't have pthreads, then we fall back to using a per-thread
+// structure.  This will leak memory if we terminate any threads with
+// exceptions in-flight.
+#ifdef NO_PTHREADS
+static __thread struct thread_data thread_data;
+#else
+void clean_tls(void *td)
+{
+	struct thread_data *data = td;
+}
+
+static pthread_key_t key;
+void init_key(void)
+{
+	pthread_key_create(&key, clean_tls);
+}
+#endif
+
+struct thread_data *get_thread_data(void)
+{
+#ifndef NO_PTHREADS
+	static pthread_once_t once_control = PTHREAD_ONCE_INIT;
+	pthread_once(&once_control, init_key);
+	struct thread_data *td = pthread_getspecific(key);
+	if (td == NULL)
+	{
+		td = calloc(sizeof(struct thread_data), 1);
+		pthread_setspecific(key, td);
+		if (pthread_getspecific(key) == NULL)
+		{
+			fprintf(stderr, "Unable to allocate thread-local storage for exceptions\n");
+		}
+	}
+	return td;
+#else
+	return &td;
+#endif
+}
+
+struct thread_data *get_thread_data_fast(void)
+{
+#ifndef NO_PTHREADS
+	struct thread_data *td = pthread_getspecific(key);
+	return td;
+#else
+	return &td;
+#endif
+}
+
+id objc_begin_catch(struct _Unwind_Exception *exceptionObject)
+{
+	struct thread_data *td = get_thread_data();
+	DEBUG_LOG("Beginning catch %p\n", exceptionObject);
+	if (exceptionObject->exception_class == objc_exception_class)
+	{
+		td->current_exception_type = OBJC;
+		struct objc_exception *ex = objc_exception_from_header(exceptionObject);
+		if (ex->catch_count == 0)
+		{
+			// If this is the first catch, add it to the list.
+			ex->catch_count = 1;
+			ex->next = td->caughtExceptions;
+			td->caughtExceptions = ex;
+		}
+		else if (ex->catch_count < 0)
+		{
+			// If this is being thrown, mark it as caught again and increment
+			// the refcount
+			ex->catch_count = -ex->catch_count + 1;
+		}
+		else
+		{
+			// Otherwise, just increment the catch count
+			ex->catch_count++;
+		}
+		DEBUG_LOG("objc catch\n");
+		return ex->object;
+	}
+	// If we have a foreign exception while we have stacked exceptions, we have
+	// a problem.  We can't chain them, so we follow the example of C++ and
+	// just abort.
+	if (td->caughtExceptions != 0)
+	{
+		// FIXME: Actually, we can handle a C++ exception if only ObjC
+		// exceptions are in-flight
+		abort();
+	}
+	// If this is a C++ exception, let the C++ runtime handle it.
+	if (exceptionObject->exception_class == cxx_exception_class)
+	{
+		DEBUG_LOG("c++ catch\n");
+		td->current_exception_type = CXX;
+		return __cxa_begin_catch(exceptionObject);
+	}
+	DEBUG_LOG("foreign exception catch\n");
+	// Box if we have a boxing function.
+	if (_objc_class_for_boxing_foreign_exception)
+	{
+		Class thrown_class =
+			_objc_class_for_boxing_foreign_exception(exceptionObject->exception_class);
+		SEL box_sel = sel_registerName("exceptionWithForeignException:");
+		IMP boxfunction = objc_msg_lookup((id)thrown_class, box_sel);
+		if (boxfunction != 0)
+		{
+			id boxed = boxfunction((id)thrown_class, box_sel, exceptionObject);
+			td->caughtExceptions = (struct objc_exception*)boxed;
+			td->current_exception_type = BOXED_FOREIGN;
+			return boxed;
+		}
+	}
+	td->current_exception_type = FOREIGN;
+	td->caughtExceptions = (struct objc_exception*)exceptionObject;
+	// If this is some other kind of exception, then assume that the value is
+	// at the end of the exception header.
+	return (id)((char*)exceptionObject + sizeof(struct _Unwind_Exception));
+}
+
+void objc_end_catch(void)
+{
+	struct thread_data *td = get_thread_data_fast();
+	// If this is a boxed foreign exception then the boxing class is
+	// responsible for cleaning it up
+	if (td->current_exception_type == BOXED_FOREIGN)
+	{
+		td->caughtExceptions = 0;
+		td->current_exception_type = NONE;
+		return;
+	}
+	DEBUG_LOG("Ending catch\n");
+	// If this is a C++ exception, then just let the C++ runtime handle it.
+	if (td->current_exception_type == CXX)
+	{
+		__cxa_end_catch();
+		td->current_exception_type = OBJC;
+		return;
+	}
+	if (td->current_exception_type == FOREIGN)
+	{
+		struct _Unwind_Exception *e = ((struct _Unwind_Exception*)td->caughtExceptions);
+		e->exception_cleanup(_URC_FOREIGN_EXCEPTION_CAUGHT, e);
+		td->current_exception_type = NONE;
+		td->caughtExceptions = 0;
+		return;
+	}
+	// Otherwise we should do the cleanup thing.  Nested catches are possible,
+	// so we only clean up the exception if this is the last reference.
+	assert(td->caughtExceptions != 0);
+	struct objc_exception *ex = td->caughtExceptions;
+	// If this is being rethrown decrement its (negated) catch count, but don't
+	// delete it even if its catch count would be 0.
+	if (ex->catch_count < 0)
+	{
+		ex->catch_count++;
+		return;
+	}
+	ex->catch_count--;
+	if (ex->catch_count == 0)
+	{
+		td->caughtExceptions = ex->next;
+		free(ex);
+	}
+}
+
+void objc_exception_rethrow(struct _Unwind_Exception *e)
+{
+	struct thread_data *td = get_thread_data_fast();
+	// If this is an Objective-C exception, then 
+	if (td->current_exception_type == OBJC)
+	{
+		struct objc_exception *ex = objc_exception_from_header(e);
+		assert(e->exception_class == objc_exception_class);
+		assert(ex == td->caughtExceptions);
+		assert(ex->catch_count > 0);
+		// Negate the catch count, so that we can detect that this is a
+		// rethrown exception in objc_end_catch
+		ex->catch_count = -ex->catch_count;
+		_Unwind_Reason_Code err = _Unwind_Resume_or_Rethrow(e);
+		free(ex);
+		if (_URC_END_OF_STACK == err && 0 != _objc_unexpected_exception)
+		{
+			_objc_unexpected_exception(ex->object);
+		}
+		abort();
+	}
+	else if (td->current_exception_type == CXX)
+	{
+		assert(e->exception_class == cxx_exception_class);
+		__cxa_rethrow();
+	}
+	if (td->current_exception_type == BOXED_FOREIGN)
+	{
+		SEL rethrow_sel = sel_registerName("rethrow");
+		id object = (id)td->caughtExceptions;
+		if ((nil != object) &&
+		    (class_respondsToSelector(classForObject(object), rethrow_sel)))
+		{
+			DEBUG_LOG("Rethrowing boxed exception\n");
+			IMP rethrow = objc_msg_lookup(object, rethrow_sel);
+			rethrow(object, rethrow_sel);
+		}
+	}
+	assert(e == (struct _Unwind_Exception*)td->caughtExceptions);
+	_Unwind_Resume_or_Rethrow(e);
+	abort();
+}
diff --git a/third_party/libobjc/encoding2.c b/third_party/libobjc/encoding2.c
index 5c9b4edcf1..439c5aca60 100644
--- a/third_party/libobjc/encoding2.c
+++ b/third_party/libobjc/encoding2.c
@@ -4,6 +4,7 @@
 #include <ctype.h>
 
 #include "objc/runtime.h"
+#include "objc/encoding.h"
 #include "method_list.h"
 #include "visibility.h"
 
@@ -449,32 +450,23 @@ char* method_copyReturnType(Method method)
 unsigned objc_get_type_qualifiers (const char *type)
 {
 	unsigned flags = 0;
-#define MAP(chr, bit) case chr: flags |= (1<<bit); break;
+#define MAP(chr, bit) case chr: flags |= 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)
+			MAP('r', _F_CONST)
+			MAP('n', _F_IN)
+			MAP('o', _F_OUT)
+			MAP('N', _F_INOUT)
+			MAP('O', _F_BYCOPY)
+			MAP('V', _F_ONEWAY)
+			MAP('R', _F_BYREF)
 		}
 	} 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)
diff --git a/third_party/libobjc/hash_table.h b/third_party/libobjc/hash_table.h
index e064af1782..951bd2d7a1 100644
--- a/third_party/libobjc/hash_table.h
+++ b/third_party/libobjc/hash_table.h
@@ -199,6 +199,7 @@ static int PREFIX(_table_resize)(PREFIX(_table) *table)
 	__sync_synchronize();
 	table->old = NULL;
 #	if !defined(ENABLE_GC) && defined(MAP_TABLE_SINGLE_THREAD)
+	free(copy->table);
 	free(copy);
 #	endif
 	return 1;
diff --git a/third_party/libobjc/loader.c b/third_party/libobjc/loader.c
index 67a8cf5b95..6f4d88e06d 100644
--- a/third_party/libobjc/loader.c
+++ b/third_party/libobjc/loader.c
@@ -25,6 +25,13 @@ void init_selector_tables(void);
 void init_trampolines(void);
 void objc_send_load_message(Class class);
 
+void log_selector_memory_usage(void);
+
+static void log_memory_stats(void)
+{
+	log_selector_memory_usage();
+}
+
 /* Number of threads that are alive.  */
 int __objc_runtime_threads_alive = 1;			/* !T:MUTEX */
 
@@ -62,6 +69,10 @@ void __objc_exec_class(struct objc_module_abi_8 *module)
 		init_arc();
 		init_trampolines();
 		first_run = NO;
+		if (getenv("LIBOBJC_MEMORY_PROFILE"))
+		{
+			atexit(log_memory_stats);
+		}
 	}
 
 	// The runtime mutex is held for the entire duration of a load.  It does
diff --git a/third_party/libobjc/lock.h b/third_party/libobjc/lock.h
index 1ec7a68d99..03656818c0 100644
--- a/third_party/libobjc/lock.h
+++ b/third_party/libobjc/lock.h
@@ -22,7 +22,7 @@ typedef HANDLE mutex_t;
 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
-#	define INIT_LOCK(x) init_recursive_mutex(&(x))
+#		define INIT_LOCK(x) init_recursive_mutex(&(x))
 
 static inline void init_recursive_mutex(pthread_mutex_t *x)
 {
diff --git a/third_party/libobjc/objc/Availability.h b/third_party/libobjc/objc/Availability.h
index 408b9988ca..0bdc7cda55 100644
--- a/third_party/libobjc/objc/Availability.h
+++ b/third_party/libobjc/objc/Availability.h
@@ -1,3 +1,7 @@
+#if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__)
+#pragma clang system_header
+#endif
+
 
 #ifdef STRICT_MACOS_X
 #	define OBJC_NONPORTABLE __attribute__((error("Function not supported by the Apple runtime")))
diff --git a/third_party/libobjc/objc/Object.h b/third_party/libobjc/objc/Object.h
index e5c9c4669d..b37647d648 100644
--- a/third_party/libobjc/objc/Object.h
+++ b/third_party/libobjc/objc/Object.h
@@ -1,3 +1,7 @@
+#if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__)
+#pragma clang system_header
+#endif
+
 #include <objc/runtime.h>
 
 @interface Object
diff --git a/third_party/libobjc/objc/Protocol.h b/third_party/libobjc/objc/Protocol.h
index d38c1f51d3..b67085dd56 100644
--- a/third_party/libobjc/objc/Protocol.h
+++ b/third_party/libobjc/objc/Protocol.h
@@ -1,3 +1,7 @@
+#if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__)
+#pragma clang system_header
+#endif
+
 #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
index 5f1fca1558..60a1d590ac 100644
--- a/third_party/libobjc/objc/blocks_private.h
+++ b/third_party/libobjc/objc/blocks_private.h
@@ -1,5 +1,9 @@
 #ifndef __LIBOBJC_BLOCKS_PRIVATE_H_INCLUDED__
 #define __LIBOBJC_BLOCKS_PRIVATE_H_INCLUDED__
+#if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__)
+#pragma clang system_header
+#endif
+
 
 /*
  * This header file exposes some implementation details of the blocks runtime
diff --git a/third_party/libobjc/objc/blocks_runtime.h b/third_party/libobjc/objc/blocks_runtime.h
index 8a64bf2fd5..e5dbdea6f0 100644
--- a/third_party/libobjc/objc/blocks_runtime.h
+++ b/third_party/libobjc/objc/blocks_runtime.h
@@ -1,3 +1,7 @@
+#if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__)
+#pragma clang system_header
+#endif
+
 /*
  * Blocks Runtime
  */
diff --git a/third_party/libobjc/objc/capabilities.h b/third_party/libobjc/objc/capabilities.h
index 950749c080..dc4e046471 100644
--- a/third_party/libobjc/objc/capabilities.h
+++ b/third_party/libobjc/objc/capabilities.h
@@ -1,3 +1,7 @@
+#if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__)
+#pragma clang system_header
+#endif
+
 /**
  * capabilities.h - This file defines the list of capabilities.  Runtime
  * capabilities can be checked.  You may use #ifdef to test at compile time
diff --git a/third_party/libobjc/objc/developer.h b/third_party/libobjc/objc/developer.h
index 2752cf12d5..321ea8d424 100644
--- a/third_party/libobjc/objc/developer.h
+++ b/third_party/libobjc/objc/developer.h
@@ -1,3 +1,7 @@
+#if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__)
+#pragma clang system_header
+#endif
+
 enum objc_developer_mode_np
 {
 	/** User mode - the default. */
diff --git a/third_party/libobjc/objc/encoding.h b/third_party/libobjc/objc/encoding.h
index bb58c0b8c4..4c4ff53b15 100644
--- a/third_party/libobjc/objc/encoding.h
+++ b/third_party/libobjc/objc/encoding.h
@@ -1,3 +1,7 @@
+#if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__)
+#pragma clang system_header
+#endif
+
 #ifndef __LIBOBJC_ENCODING_H_INCLUDED__
 #define __LIBOBJC_ENCODING_H_INCLUDED__
 
diff --git a/third_party/libobjc/objc/hooks.h b/third_party/libobjc/objc/hooks.h
index 7fdcf88091..8ec6b70e6e 100644
--- a/third_party/libobjc/objc/hooks.h
+++ b/third_party/libobjc/objc/hooks.h
@@ -1,3 +1,7 @@
+#if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__)
+#pragma clang system_header
+#endif
+
 /**
  * This file includes all of the hooks that can be used to alter the behaviour
  * of the runtime.  
diff --git a/third_party/libobjc/objc/message.h b/third_party/libobjc/objc/message.h
new file mode 100644
index 0000000000..ed946950e4
--- /dev/null
+++ b/third_party/libobjc/objc/message.h
@@ -0,0 +1,62 @@
+#if defined(__clang__)
+#pragma clang system_header
+#endif
+
+#ifndef _OBJC_MESSAGE_H_
+#define _OBJC_MESSAGE_H_
+
+#if defined(__x86_64) || defined(__i386) || defined(__arm__) || \
+	defined(__mips_n64) || defined(__mips_n32)
+/**
+ * Standard message sending function.  This function must be cast to the
+ * correct types for the function before use.  The first argument is the
+ * receiver and the second the selector.
+ *
+ * Note that this function is not available on all architectures.  For a more
+ * portable solution to sending arbitrary messages, consider using
+ * objc_msg_lookup_sender() and then calling the returned IMP directly.
+ *
+ * This version of the function is used for all messages that return either an
+ * integer, a pointer, or a small structure value that is returned in
+ * registers.  Be aware that calling conventions differ between operating
+ * systems even within the same architecture, so take great care if using this
+ * function for small (two integer) structures.
+ */
+id objc_msgSend(id self, SEL _cmd, ...);
+/**
+ * Standard message sending function.  This function must be cast to the
+ * correct types for the function before use.  The first argument is the
+ * receiver and the second the selector.
+ *
+ * Note that this function is not available on all architectures.  For a more
+ * portable solution to sending arbitrary messages, consider using
+ * objc_msg_lookup_sender() and then calling the returned IMP directly.
+ *
+ * This version of the function is used for all messages that return a
+ * structure that is not returned in registers.  Be aware that calling
+ * conventions differ between operating systems even within the same
+ * architecture, so take great care if using this function for small (two
+ * integer) structures.
+ */
+#ifdef __cplusplus 
+id objc_msgSend_stret(id self, SEL _cmd, ...);
+#else
+void objc_msgSend_stret(id self, SEL _cmd, ...);
+#endif
+/**
+ * Standard message sending function.  This function must be cast to the
+ * correct types for the function before use.  The first argument is the
+ * receiver and the second the selector.
+ *
+ * Note that this function is not available on all architectures.  For a more
+ * portable solution to sending arbitrary messages, consider using
+ * objc_msg_lookup_sender() and then calling the returned IMP directly.
+ *
+ * This version of the function is used for all messages that return floating
+ * point values.
+ */
+long double objc_msgSend_fpret(id self, SEL _cmd, ...);
+
+#endif
+
+#endif //_OBJC_MESSAGE_H_
diff --git a/third_party/libobjc/objc/objc-api.h b/third_party/libobjc/objc/objc-api.h
index 9786447367..9cf4aaf894 100644
--- a/third_party/libobjc/objc/objc-api.h
+++ b/third_party/libobjc/objc/objc-api.h
@@ -1 +1,5 @@
+#if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__)
+#pragma clang system_header
+#endif
+
 #include <objc/runtime.h>
diff --git a/third_party/libobjc/objc/objc-arc.h b/third_party/libobjc/objc/objc-arc.h
index c7a420038d..0da4030928 100644
--- a/third_party/libobjc/objc/objc-arc.h
+++ b/third_party/libobjc/objc/objc-arc.h
@@ -1,3 +1,7 @@
+#if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__)
+#pragma clang system_header
+#endif
+
 #ifndef __OBJC_ARC_INCLUDED__
 #define __OBJC_ARC_INCLUDED__
 /**
diff --git a/third_party/libobjc/objc/objc-auto.h b/third_party/libobjc/objc/objc-auto.h
index 2ec4939574..1dfe132f99 100644
--- a/third_party/libobjc/objc/objc-auto.h
+++ b/third_party/libobjc/objc/objc-auto.h
@@ -1,3 +1,7 @@
+#if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__)
+#pragma clang system_header
+#endif
+
 /**
  * objc-auto.h - This file provides the interface for Objective-C garbage
  * collection
diff --git a/third_party/libobjc/objc/runtime-deprecated.h b/third_party/libobjc/objc/runtime-deprecated.h
index f85d3df27a..2f6c78ad3d 100644
--- a/third_party/libobjc/objc/runtime-deprecated.h
+++ b/third_party/libobjc/objc/runtime-deprecated.h
@@ -1,3 +1,7 @@
+#if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__)
+#pragma clang system_header
+#endif
+
 #if !defined(__GNUSTEP_LIBOBJC_RUNTIME_DEPRECATED_INCLUDED__) && !defined(GNUSTEP_LIBOBJC_NO_LEGACY)
 #	define __GNUSTEP_LIBOBJC_RUNTIME_DEPRECATED_INCLUDED__
 
diff --git a/third_party/libobjc/objc/runtime.h b/third_party/libobjc/objc/runtime.h
index 86c67ed5a2..3092f72e34 100644
--- a/third_party/libobjc/objc/runtime.h
+++ b/third_party/libobjc/objc/runtime.h
@@ -1,3 +1,7 @@
+#if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__)
+#pragma clang system_header
+#endif
+
 #ifndef __LIBOBJC_RUNTIME_H_INCLUDED__
 #define __LIBOBJC_RUNTIME_H_INCLUDED__
 
@@ -208,6 +212,8 @@ typedef struct
 #endif
 
 #include "slot.h"
+#include "message.h"
+
 
 /**
  * Adds an instance variable to the named class.  The class must not have been
diff --git a/third_party/libobjc/objc/slot.h b/third_party/libobjc/objc/slot.h
index 0afd7548ad..cae2ee322d 100644
--- a/third_party/libobjc/objc/slot.h
+++ b/third_party/libobjc/objc/slot.h
@@ -1,3 +1,7 @@
+#if defined(__clang__) && !defined(__OBJC_RUNTIME_INTERNAL__)
+#pragma clang system_header
+#endif
+
 #ifndef __OBJC_SLOT_H_INCLUDED__
 #define __OBJC_SLOT_H_INCLUDED__
 /**
diff --git a/third_party/libobjc/objc_msgSend.x86-32.S b/third_party/libobjc/objc_msgSend.x86-32.S
index f55f8c3c44..452cc7541b 100644
--- a/third_party/libobjc/objc_msgSend.x86-32.S
+++ b/third_party/libobjc/objc_msgSend.x86-32.S
@@ -76,11 +76,14 @@
 
 
 	jmp   *%eax
-6:                                        # smallObject:
+6:                                       # smallObject:
 	push  %ebx                           # Save old %ebx
-	call  __i686.get_pc_thunk.bx
-	addl  $_GLOBAL_OFFSET_TABLE_, %ebx
-	mov   SmallObjectClasses@GOT(%ebx), %eax
+	calll 7f
+7:
+	popl  %ebx;
+8:
+	addl  $_GLOBAL_OFFSET_TABLE_+(8b-7b), %ebx
+	leal  SmallObjectClasses@GOTOFF(%ebx), %eax
 	mov   (%eax), %eax
 	popl  %ebx
 	jmp   1b 
diff --git a/third_party/libobjc/objc_msgSend.x86-64.S b/third_party/libobjc/objc_msgSend.x86-64.S
index 8ce012baf0..62d78daa59 100644
--- a/third_party/libobjc/objc_msgSend.x86-64.S
+++ b/third_party/libobjc/objc_msgSend.x86-64.S
@@ -95,7 +95,7 @@
 	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
+	mov   %rdx, %rsi                     # move _cmd to where the callee expects it to be
 .endif
 
 	.cfi_adjust_cfa_offset 0xD8
diff --git a/third_party/libobjc/objcxx_eh.cc b/third_party/libobjc/objcxx_eh.cc
index 0a29c3ce73..7893e61d90 100644
--- a/third_party/libobjc/objcxx_eh.cc
+++ b/third_party/libobjc/objcxx_eh.cc
@@ -29,7 +29,6 @@ namespace std
 				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);
@@ -38,6 +37,7 @@ namespace std
 				protected:
 				type_info(const char *name): __type_name(name) { }
 				public:
+				const char* name() const { return __type_name; }
 				virtual bool __is_pointer_p() const;
 				virtual bool __is_function_p() const;
 				virtual bool __do_catch(const type_info *thrown_type,
@@ -214,7 +214,7 @@ struct _Unwind_Exception *objc_init_cxx_exception(void *thrown_exception)
 	return &ex->unwindHeader;
 }
 
-void* objc_object_for_cxx_exception(void *thrown_exception)
+void* objc_object_for_cxx_exception(void *thrown_exception, int *isValid)
 {
 	__cxa_exception *ex = (__cxa_exception*) ((char*)thrown_exception -
 			offsetof(struct __cxa_exception, unwindHeader));
@@ -222,8 +222,10 @@ void* objc_object_for_cxx_exception(void *thrown_exception)
 	if (!dynamic_cast<const gnustep::libobjc::__objc_id_type_info*>(thrownType) && 
 	    !dynamic_cast<const gnustep::libobjc::__objc_class_type_info*>(thrownType))
 	{
-		return (id)-1;
+		*isValid = 0;
+		return 0;
 	}
+	*isValid = 1;
 	return *(id*)(ex+1);
 }
 
diff --git a/third_party/libobjc/objcxx_eh.h b/third_party/libobjc/objcxx_eh.h
index 9866105504..987479c1de 100644
--- a/third_party/libobjc/objcxx_eh.h
+++ b/third_party/libobjc/objcxx_eh.h
@@ -28,11 +28,11 @@ __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.
+ * if it does.  The second argument is a pointer to a boolean value indicating
+ * whether this is a valid object.
  */
 __attribute__((weak))
-void *objc_object_for_cxx_exception(void *thrown_exception);
+void *objc_object_for_cxx_exception(void *thrown_exception, int *isValid);
 
 /**
  * Prints the type info associated with an exception.  Used only when
diff --git a/third_party/libobjc/opts/CMakeLists.txt b/third_party/libobjc/opts/CMakeLists.txt
index e017de8fb0..aa3f7947b5 100644
--- a/third_party/libobjc/opts/CMakeLists.txt
+++ b/third_party/libobjc/opts/CMakeLists.txt
@@ -1,3 +1,13 @@
+cmake_minimum_required(VERSION 2.8)
+
+find_package(LLVM)
+include(AddLLVM)
+
+add_definitions(${LLVM_DEFINITIONS})
+include_directories(${LLVM_INCLUDE_DIRS})
+link_directories(${LLVM_LIBRARY_DIRS})
+
+
 add_llvm_loadable_module( libGNUObjCRuntime
   ClassIMPCache.cpp
   ClassMethodInliner.cpp
@@ -10,13 +20,22 @@ add_llvm_loadable_module( libGNUObjCRuntime
   TypeFeedback.cpp
 )
 
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-variadic-macros -DLLVM_MAJOR=3 -DLLVM_MINOR=0")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-variadic-macros")
+
+set(CMAKE_CXX "clang++")
+
+EXEC_PROGRAM(llvm-config
+	ARGS --src-root
+	OUTPUT_VARIABLE LLVM_SRC)
+EXEC_PROGRAM(llvm-config
+	ARGS --obj-root
+	OUTPUT_VARIABLE LLVM_OBJ)
+EXEC_PROGRAM(llvm-config
+	ARGS --version
+	OUTPUT_VARIABLE LLVM_VER)
+
+string(REGEX REPLACE "([0-9]*).([0-9]*).*" "-DLLVM_MAJOR=\\1 -DLLVM_MINOR=\\2" LLVM_VERSION "${LLVM_VER}")
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${LLVM_VERSION} -fno-rtti")
+include_directories( ${LLVM_INCLUDE_DIRS} "${LLVM_SRC}/include/" "${LLVM_OBJ}/include/")
 
-add_llvm_library_dependencies( libGNUObjCRuntime
-  LLVMAnalysis
-  LLVMCore
-  LLVMSupport
-  LLVMTarget
-  LLVMipa
-  LLVMipo
-)
diff --git a/third_party/libobjc/opts/ClassIMPCache.cpp b/third_party/libobjc/opts/ClassIMPCache.cpp
index e427eeca6c..5f420d88bd 100644
--- a/third_party/libobjc/opts/ClassIMPCache.cpp
+++ b/third_party/libobjc/opts/ClassIMPCache.cpp
@@ -1,14 +1,6 @@
 #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>
diff --git a/third_party/libobjc/opts/ClassLookupCache.cpp b/third_party/libobjc/opts/ClassLookupCache.cpp
index 0f74cf0e46..e41aabe7c4 100644
--- a/third_party/libobjc/opts/ClassLookupCache.cpp
+++ b/third_party/libobjc/opts/ClassLookupCache.cpp
@@ -1,14 +1,6 @@
-#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>
 
@@ -50,7 +42,7 @@ namespace
         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 (Function *func = dyn_cast<Function>(call->getCalledValue()->stripPointerCasts())) {
               if (func->getName() == "objc_lookup_class") {
                 ClassLookup lookup;
                 GlobalVariable *classNameVar = dyn_cast<GlobalVariable>(
@@ -79,7 +71,6 @@ namespace
         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) {
@@ -88,6 +79,7 @@ namespace
           Value *cls = new BitCastInst(global, clsTy, "class", lookup);
           lookup->replaceAllUsesWith(cls);
           lookup->removeFromParent();
+          delete lookup;
         } else {
           GlobalVariable *cache = statics[cls];
           if (!cache) {
diff --git a/third_party/libobjc/opts/ClassMethodInliner.cpp b/third_party/libobjc/opts/ClassMethodInliner.cpp
index dff8b7154a..7d061f30ef 100644
--- a/third_party/libobjc/opts/ClassMethodInliner.cpp
+++ b/third_party/libobjc/opts/ClassMethodInliner.cpp
@@ -1,15 +1,6 @@
-#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>
diff --git a/third_party/libobjc/opts/IMPCacher.cpp b/third_party/libobjc/opts/IMPCacher.cpp
index b6b5f49e51..5b354c16c8 100644
--- a/third_party/libobjc/opts/IMPCacher.cpp
+++ b/third_party/libobjc/opts/IMPCacher.cpp
@@ -1,13 +1,5 @@
 #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"
diff --git a/third_party/libobjc/opts/IvarPass.cpp b/third_party/libobjc/opts/IvarPass.cpp
index 648901bb38..5760963202 100644
--- a/third_party/libobjc/opts/IvarPass.cpp
+++ b/third_party/libobjc/opts/IvarPass.cpp
@@ -1,12 +1,5 @@
-#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 "LLVMCompat.h"
 #include "llvm/Analysis/Verifier.h"
-#include "llvm/DefaultPasses.h"
 #include "llvm/ADT/DenseSet.h"
 #include "ObjectiveCOpts.h"
 #include <string>
@@ -156,7 +149,6 @@ namespace {
               end=replacements.end() ; i != end ; ++i) {
         if (i->second) 
           i->first->replaceAllUsesWith(i->second);
-        i->first->removeFromParent();
       }
       verifyFunction(F);
       return modified;
diff --git a/third_party/libobjc/opts/LLVMCompat.h b/third_party/libobjc/opts/LLVMCompat.h
index 85f472ceb4..2a37344e06 100644
--- a/third_party/libobjc/opts/LLVMCompat.h
+++ b/third_party/libobjc/opts/LLVMCompat.h
@@ -7,11 +7,39 @@
 
 #ifndef __LANGUAGEKIT_LLVM_HACKS__
 #define __LANGUAGEKIT_LLVM_HACKS__
+#if LLVM_MAJOR < 3 || (LLVM_MAJOR >=3 && LLVM_MINOR <= 2)
+#if LLVM_MAJOR < 3 || (LLVM_MAJOR >=3 && LLVM_MINOR <= 1)
+#include <llvm/Support/IRBuilder.h>
+#else
+#include <llvm/IRBuilder.h>
+#endif
+#include <llvm/Function.h>
+#include <llvm/Module.h>
+#include <llvm/LLVMContext.h>
 #include <llvm/Instructions.h>
 #include <llvm/Metadata.h>
 #include <llvm/Intrinsics.h>
-#include <llvm/Support/IRBuilder.h>
+#include <llvm/Constants.h>
+#include <llvm/GlobalAlias.h>
+#include <llvm/GlobalVariable.h>
+#include <llvm/DefaultPasses.h>
+#else
+#include <llvm/IR/IRBuilder.h>
+#include <llvm/IR/Function.h>
+#include <llvm/IR/Module.h>
+#include <llvm/IR/LLVMContext.h>
+#include <llvm/IR/Instructions.h>
+#include <llvm/IR/Metadata.h>
+#include <llvm/IR/Intrinsics.h>
+#include <llvm/IR/Constants.h>
+#include <llvm/IR/GlobalVariable.h>
+#include <llvm/IR/GlobalAlias.h>
+#include <llvm/PassSupport.h>
+#endif
 
+#if (LLVM_MAJOR > 3) || ((LLVM_MAJOR == 3) && (LLVM_MINOR >= 3))
+#	define InlineCostAnalyzer InlineCostAnalysis
+#endif
 
 // Only preserve names in a debug build.  This simplifies the
 // IR in a release build, but makes it much harder to debug.
diff --git a/third_party/libobjc/opts/LoopIMPCachePass.cpp b/third_party/libobjc/opts/LoopIMPCachePass.cpp
index 21fcfe1a3a..317a04cd27 100644
--- a/third_party/libobjc/opts/LoopIMPCachePass.cpp
+++ b/third_party/libobjc/opts/LoopIMPCachePass.cpp
@@ -1,13 +1,6 @@
-#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 "LLVMCompat.h"
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/Analysis/Verifier.h"
-#include "llvm/DefaultPasses.h"
 #include "ObjectiveCOpts.h"
 #include "IMPCacher.h"
 #include <string>
diff --git a/third_party/libobjc/opts/ObjectiveCOpts.cpp b/third_party/libobjc/opts/ObjectiveCOpts.cpp
index 9cc64048a9..fa585f7767 100644
--- a/third_party/libobjc/opts/ObjectiveCOpts.cpp
+++ b/third_party/libobjc/opts/ObjectiveCOpts.cpp
@@ -1,8 +1,7 @@
-#include "llvm/Pass.h"
-#include "llvm/Module.h"
+#include "LLVMCompat.h"
 #if LLVM_MAJOR >= 3
-#include "llvm/Transforms/IPO/PassManagerBuilder.h"
-#include "llvm/PassManager.h"
+#include <llvm/Transforms/IPO/PassManagerBuilder.h>
+#include <llvm/PassManager.h>
 #endif
 
 #include "ObjectiveCOpts.h"
diff --git a/third_party/libobjc/opts/TypeFeedback.cpp b/third_party/libobjc/opts/TypeFeedback.cpp
index 8c940ef54f..e2988a00f0 100644
--- a/third_party/libobjc/opts/TypeFeedback.cpp
+++ b/third_party/libobjc/opts/TypeFeedback.cpp
@@ -1,11 +1,5 @@
-#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 <llvm/Support/CallSite.h>
+#include <llvm/Linker.h>
 #include <vector>
 
 using namespace llvm;
@@ -131,7 +125,12 @@ namespace {
             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->isConstant(), GCL->getLinkage(), CA, "", 
+#if LLVM_MAJOR < 3 || (LLVM_MAJOR == 3 && LLVM_MINOR < 2)
+          GCL->isThreadLocal());
+#else
+          GCL->	getThreadLocalMode());
+#endif
       GCL->getParent()->getGlobalList().insert(GCL, NGV);
       NGV->takeName(GCL);
       GCL->replaceAllUsesWith(NGV);
diff --git a/third_party/libobjc/opts/TypeFeedbackDrivenInliner.cpp b/third_party/libobjc/opts/TypeFeedbackDrivenInliner.cpp
index a189f03c2b..050c8be416 100644
--- a/third_party/libobjc/opts/TypeFeedbackDrivenInliner.cpp
+++ b/third_party/libobjc/opts/TypeFeedbackDrivenInliner.cpp
@@ -1,9 +1,4 @@
-#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 "LLVMCompat.h"
 #include "llvm/Analysis/InlineCost.h"
 #include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/Linker.h"
diff --git a/third_party/libobjc/opts/TypeInfoProvider.h b/third_party/libobjc/opts/TypeInfoProvider.h
index cd659bf3c7..be50c362a5 100644
--- a/third_party/libobjc/opts/TypeInfoProvider.h
+++ b/third_party/libobjc/opts/TypeInfoProvider.h
@@ -1,12 +1,5 @@
+#include "LLVMCompat.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"
diff --git a/third_party/libobjc/pool.h b/third_party/libobjc/pool.h
index ffa8a6ad7c..f0bd5451e7 100644
--- a/third_party/libobjc/pool.h
+++ b/third_party/libobjc/pool.h
@@ -29,13 +29,17 @@ static mutex_t NAME(_lock);
 #define UNLOCK_POOL()
 #endif
 
+static int pool_size = 0;
+static int pool_allocs = 0;
 static inline POOL_TYPE*NAME(_pool_alloc)(void)
 {
 	LOCK_POOL();
+	pool_allocs++;
 	if (0 > NAME(_pool_next_index))
 	{
 		NAME(_pool) = malloc(PAGE_SIZE);
 		NAME(_pool_next_index) = POOL_SIZE - 1;
+		pool_size += PAGE_SIZE;
 	}
 	POOL_TYPE* new = &NAME(_pool)[NAME(_pool_next_index)--];
 	UNLOCK_POOL();
diff --git a/third_party/libobjc/properties.h b/third_party/libobjc/properties.h
index 9500ac56ee..a9ac581384 100644
--- a/third_party/libobjc/properties.h
+++ b/third_party/libobjc/properties.h
@@ -40,6 +40,50 @@ enum PropertyAttributeKind
 	OBJC_PR_setter    = (1<<7)
 };
 
+/**
+ * Flags in the second attributes field in declared properties.
+ * Note: This field replaces the old 'is synthesized' field and so these values
+ * are shifted left one from their values in clang.
+ */
+enum PropertyAttributeKind2
+{
+	/**
+	 * No extended attributes.
+	 */
+	OBJC_PR_noextattr         = 0,
+	/**
+	 * The property is synthesized.  This has no meaning in properties on
+	 * protocols.
+	 */
+	OBJC_PR_synthesized       = (1<<0),
+	/**
+	 * The property is dynamic (i.e. the implementation is inherited or
+	 * provided at run time).
+	 */
+	OBJC_PR_dynamic           = (1<<1),
+	/**
+	 * This property belongs to a protocol.
+	 */
+	OBJC_PR_protocol          = OBJC_PR_synthesized | OBJC_PR_dynamic,
+	/**
+	 * The property is atomic.
+	 */
+	OBJC_PR_atomic            = (1<<2),
+	/**
+	 * The property value is a zeroing weak reference.
+	 */
+	OBJC_PR_weak              = (1<<3),
+	/**
+	 * The property value is strong (retained).  Currently, this is equivalent
+	 * to the strong attribute.
+	 */
+	OBJC_PR_strong            = (1<<4),
+	/**
+	 * The property value is just copied.
+	 */
+	OBJC_PR_unsafe_unretained = (1<<5),
+};
+
 /**
  * Structure used for property enumeration.  Note that property enumeration is
  * currently quite broken on OS X, so achieving full compatibility there is
@@ -60,7 +104,17 @@ struct objc_property
 	/**
 	 * Flag set if the property is synthesized.
 	 */
-	const char isSynthesized;
+	char attributes2;
+	/**
+	 * Padding field.  These were implicit in the structure field alignment
+	 * (four more on 64-bit platforms), but we'll make them explicit now for
+	 * future use.
+	 */
+	char unused1;
+	/**
+	 * More padding.
+	 */
+	char unused2;
 	/**
 	 * Name of the getter for this property.
 	 */
@@ -99,7 +153,16 @@ struct objc_property_list
 };
 
 /**
- * Constructs a property description from a list of attributes.
+ * Constructs a property description from a list of attributes, returning the
+ * instance variable name via the third parameter.
  */
 PRIVATE struct objc_property propertyFromAttrs(const objc_property_attribute_t *attributes,
-                                               unsigned int attributeCount);
+                                               unsigned int attributeCount,
+                                               const char **iVarName);
+
+/**
+ * Constructs and installs a property attribute string from the property
+ * attributes and, optionally, an ivar string.
+ */
+PRIVATE const char *constructPropertyAttributes(objc_property_t property,
+                                                const char *iVarName);
diff --git a/third_party/libobjc/properties.m b/third_party/libobjc/properties.m
index fe4344d996..36930a9083 100644
--- a/third_party/libobjc/properties.m
+++ b/third_party/libobjc/properties.m
@@ -14,6 +14,11 @@
 
 PRIVATE int spinlocks[spinlock_count];
 
+static inline BOOL checkAttribute(char field, int attr)
+{
+	return (field & attr) == attr;
+}
+
 /**
  * Public function for getting a property.  
  */
@@ -84,6 +89,82 @@ void objc_setProperty(id obj, SEL _cmd, ptrdiff_t offset, id arg, BOOL isAtomic,
 	objc_release(old);
 }
 
+void objc_setProperty_atomic(id obj, SEL _cmd, id arg, ptrdiff_t offset)
+{
+	char *addr = (char*)obj;
+	addr += offset;
+	arg = objc_retain(arg);
+	volatile int *lock = lock_for_pointer(addr);
+	lock_spinlock(lock);
+	id old = *(id*)addr;
+	*(id*)addr = arg;
+	unlock_spinlock(lock);
+	objc_release(old);
+}
+
+void objc_setProperty_atomic_copy(id obj, SEL _cmd, id arg, ptrdiff_t offset)
+{
+	char *addr = (char*)obj;
+	addr += offset;
+
+	arg = [arg copy];
+	volatile int *lock = lock_for_pointer(addr);
+	lock_spinlock(lock);
+	id old = *(id*)addr;
+	*(id*)addr = arg;
+	unlock_spinlock(lock);
+	objc_release(old);
+}
+
+void objc_setProperty_nonatomic(id obj, SEL _cmd, id arg, ptrdiff_t offset)
+{
+	char *addr = (char*)obj;
+	addr += offset;
+	arg = objc_retain(arg);
+	id old = *(id*)addr;
+	*(id*)addr = arg;
+	objc_release(old);
+}
+
+void objc_setProperty_nonatomic_copy(id obj, SEL _cmd, id arg, ptrdiff_t offset)
+{
+	char *addr = (char*)obj;
+	addr += offset;
+	id old = *(id*)addr;
+	*(id*)addr = [arg copy];
+	objc_release(old);
+}
+
+void objc_copyCppObjectAtomic(void *dest, const void *src,
+                              void (*copyHelper) (void *dest, const void *source))
+{
+	volatile int *lock = lock_for_pointer(src < dest ? src : dest);
+	volatile int *lock2 = lock_for_pointer(src < dest ? dest : src);
+	lock_spinlock(lock);
+	lock_spinlock(lock2);
+	copyHelper(dest, src);
+	unlock_spinlock(lock);
+	unlock_spinlock(lock2);
+}
+
+void objc_getCppObjectAtomic(void *dest, const void *src,
+                             void (*copyHelper) (void *dest, const void *source))
+{
+	volatile int *lock = lock_for_pointer(src);
+	lock_spinlock(lock);
+	copyHelper(dest, src);
+	unlock_spinlock(lock);
+}
+
+void objc_setCppObjectAtomic(void *dest, const void *src,
+                             void (*copyHelper) (void *dest, const void *source))
+{
+	volatile int *lock = lock_for_pointer(dest);
+	lock_spinlock(lock);
+	copyHelper(dest, src);
+	unlock_spinlock(lock);
+}
+
 /**
  * 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
@@ -99,8 +180,8 @@ void objc_copyPropertyStruct(void *dest,
 {
 	if (atomic)
 	{
-		volatile int *lock = lock_for_pointer(src);
-		volatile int *lock2 = lock_for_pointer(src);
+		volatile int *lock = lock_for_pointer(src < dest ? src : dest);
+		volatile int *lock2 = lock_for_pointer(src < dest ? dest : src);
 		lock_spinlock(lock);
 		lock_spinlock(lock2);
 		memcpy(dest, src, size);
@@ -173,7 +254,7 @@ objc_property_t class_getProperty(Class cls, const char *name)
 		for (int i=0 ; i<properties->count ; i++)
 		{
 			objc_property_t p = &properties->properties[i];
-			if (strcmp(p->name, name) == 0)
+			if (strcmp(property_getName(p), name) == 0)
 			{
 				return p;
 			}
@@ -210,17 +291,33 @@ objc_property_t* class_copyPropertyList(Class cls, unsigned int *outCount)
 	{
 		for (int i=0 ; i<properties->count ; i++)
 		{
-			list[out] = &l->properties[i];
+			list[out++] = &l->properties[i];
 		}
 	}
 	return list;
 }
+static const char* property_getIVar(objc_property_t property) {
+	const char *iVar = property_getAttributes(property);
+	if (iVar != 0)
+	{
+		while ((*iVar != 0) && (*iVar != 'V'))
+		{
+			iVar++;
+		}
+		if (*iVar == 'V')
+		{
+			return iVar+1;
+		}
+	}
+	return 0;
+}
 
 const char *property_getName(objc_property_t property)
 {
 	if (NULL == property) { return NULL; }
 
 	const char *name = property->name;
+	if (NULL == name) { return NULL; }
 	if (name[0] == 0)
 	{
 		name += name[1];
@@ -238,6 +335,7 @@ PRIVATE size_t lengthOfTypeEncoding(const char *types);
 static const char *property_getTypeEncoding(objc_property_t property)
 {
 	if (NULL == property) { return NULL; }
+	if (NULL == property->getter_types) { return NULL; }
 
 	const char *name = property->getter_types;
 	if (name[0] == 0)
@@ -256,39 +354,44 @@ static const char *property_getTypeEncoding(objc_property_t property)
 	return &property->getter_types[1];
 }
 
-const char *property_getAttributes(objc_property_t property)
+PRIVATE const char *constructPropertyAttributes(objc_property_t property,
+                                                const char *iVarName)
 {
-	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);
+	size_t typeSize = (NULL == typeEncoding) ? 0 : strlen(typeEncoding);
+	size_t nameSize = (NULL == name) ? 0 : strlen(name);
+	size_t iVarNameSize = (NULL == iVarName) ? 0 : strlen(iVarName);
 	// 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];
+	char flags[20];
 	size_t i = 0;
 	// Flags that are a comma then a character
-	if ((property->attributes & OBJC_PR_readonly) == OBJC_PR_readonly)
+	if (checkAttribute(property->attributes, OBJC_PR_readonly))
 	{
 		flags[i++] = ',';
 		flags[i++] = 'R';
 	}
-	if ((property->attributes & OBJC_PR_copy) == OBJC_PR_copy)
+	if (checkAttribute(property->attributes, OBJC_PR_retain))
+	{
+		flags[i++] = ',';
+		flags[i++] = '&';
+	}
+	if (checkAttribute(property->attributes, OBJC_PR_copy))
 	{
 		flags[i++] = ',';
 		flags[i++] = 'C';
 	}
-	if ((property->attributes & OBJC_PR_retain) == OBJC_PR_retain)
+	if (checkAttribute(property->attributes2, OBJC_PR_weak))
 	{
 		flags[i++] = ',';
-		flags[i++] = '&';
+		flags[i++] = 'W';
+	}
+	if (checkAttribute(property->attributes2, OBJC_PR_dynamic))
+	{
+		flags[i++] = ',';
+		flags[i++] = 'D';
 	}
 	if ((property->attributes & OBJC_PR_nonatomic) == OBJC_PR_nonatomic)
 	{
@@ -309,36 +412,67 @@ const char *property_getAttributes(objc_property_t property)
 		setterLength = strlen(property->setter_name);
 		encodingSize += 2 + setterLength;
 	}
+	if (NULL != iVarName)
+	{
+		encodingSize += 2 + iVarNameSize;
+	}
 	unsigned char *encoding = malloc(encodingSize);
 	// Set the leading 0 and the offset of the name
 	unsigned char *insert = encoding;
+	BOOL needsComma = NO;
 	*(insert++) = 0;
 	*(insert++) = 0;
 	// Set the type encoding
-	*(insert++) = 'T';
-	memcpy(insert, typeEncoding, typeSize);
-	insert += typeSize;
+	if (NULL != typeEncoding)
+	{
+		*(insert++) = 'T';
+		memcpy(insert, typeEncoding, typeSize);
+		insert += typeSize;
+		needsComma = YES;
+	}
 	// Set the flags
 	memcpy(insert, flags, i);
 	insert += i;
 	if ((property->attributes & OBJC_PR_getter) == OBJC_PR_getter)
 	{
-		*(insert++) = ',';
+		if (needsComma)
+		{
+			*(insert++) = ',';
+		}
+		i++;
+		needsComma = YES;
 		*(insert++) = 'G';
 		memcpy(insert, property->getter_name, getterLength);
 		insert += getterLength;
 	}
 	if ((property->attributes & OBJC_PR_setter) == OBJC_PR_setter)
 	{
-		*(insert++) = ',';
+		if (needsComma)
+		{
+			*(insert++) = ',';
+		}
+		i++;
+		needsComma = YES;
 		*(insert++) = 'S';
 		memcpy(insert, property->setter_name, setterLength);
 		insert += setterLength;
 	}
-	*(insert++) = ',';
-	*(insert++) = 'V';
+	// If the instance variable name is the same as the property name, then we
+	// use the same string for both, otherwise we write the ivar name in the
+	// attributes string and then a null and then the name.
+	if (NULL != iVarName)
+	{
+		if (needsComma)
+		{
+			*(insert++) = ',';
+		}
+		*(insert++) = 'V';
+		memcpy(insert, iVarName, iVarNameSize);
+		insert += iVarNameSize;
+	}
+	*(insert++) = '\0';
 	encoding[1] = (unsigned char)(uintptr_t)(insert - encoding);
-	memcpy(insert, property->name, nameSize);
+	memcpy(insert, name, nameSize);
 	insert += nameSize;
 	*insert = '\0';
 	// If another thread installed the encoding string while we were computing
@@ -351,28 +485,66 @@ const char *property_getAttributes(objc_property_t property)
 	return (const char*)(encoding + 2);
 }
 
+
+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;
+	}
+	return constructPropertyAttributes(property, NULL);
+}
+
+
 objc_property_attribute_t *property_copyAttributeList(objc_property_t property,
                                                       unsigned int *outCount)
 {
 	if (NULL == property) { return NULL; }
-	objc_property_attribute_t attrs[10];
+	objc_property_attribute_t attrs[12];
 	int count = 0;
 
-	attrs[count].name = "T";
-	attrs[count].value = property_getTypeEncoding(property);
-	count++;
-	if ((property->attributes & OBJC_PR_copy) == OBJC_PR_copy)
+	const char *types = property_getTypeEncoding(property);
+	if (NULL != types)
+	{
+		attrs[count].name = "T";
+		attrs[count].value = types;
+		count++;
+	}
+	if (checkAttribute(property->attributes, OBJC_PR_readonly))
+	{
+		attrs[count].name = "R";
+		attrs[count].value = "";
+		count++;
+	}
+	if (checkAttribute(property->attributes, OBJC_PR_copy))
 	{
 		attrs[count].name = "C";
 		attrs[count].value = "";
 		count++;
 	}
-	if ((property->attributes & OBJC_PR_retain) == OBJC_PR_retain)
+	if (checkAttribute(property->attributes, OBJC_PR_retain) ||
+	    checkAttribute(property->attributes2, OBJC_PR_strong))
 	{
 		attrs[count].name = "&";
 		attrs[count].value = "";
 		count++;
 	}
+	if (checkAttribute(property->attributes2, OBJC_PR_dynamic) &&
+	    !checkAttribute(property->attributes2, OBJC_PR_synthesized))
+	{
+		attrs[count].name = "D";
+		attrs[count].value = "";
+		count++;
+	}
+	if (checkAttribute(property->attributes2, OBJC_PR_weak))
+	{
+		attrs[count].name = "W";
+		attrs[count].value = "";
+		count++;
+	}
 	if ((property->attributes & OBJC_PR_nonatomic) == OBJC_PR_nonatomic)
 	{
 		attrs[count].name = "N";
@@ -391,9 +563,13 @@ objc_property_attribute_t *property_copyAttributeList(objc_property_t property,
 		attrs[count].value = property->setter_name;
 		count++;
 	}
-	attrs[count].name = "V";
-	attrs[count].value = property_getName(property);
-	count++;
+	const char *name = property_getIVar(property);
+	if (name != NULL)
+	{
+		attrs[count].name = "V";
+		attrs[count].value = name;
+		count++;
+	}
 
 	objc_property_attribute_t *propAttrs = calloc(sizeof(objc_property_attribute_t), count);
 	memcpy(propAttrs, attrs, count * sizeof(objc_property_attribute_t));
@@ -405,7 +581,8 @@ objc_property_attribute_t *property_copyAttributeList(objc_property_t property,
 }
 
 PRIVATE struct objc_property propertyFromAttrs(const objc_property_attribute_t *attributes,
-                                               unsigned int attributeCount)
+                                               unsigned int attributeCount,
+                                               const char **name)
 {
 	struct objc_property p = { 0 };
 	for (unsigned int i=0 ; i<attributeCount ; i++)
@@ -434,20 +611,38 @@ PRIVATE struct objc_property propertyFromAttrs(const objc_property_attribute_t *
 			}
 			case 'V':
 			{
-				p.name = strdup(attributes[i].value);
+				*name = attributes[i].value;
 				break;
 			}
 			case 'C':
 			{
 				p.attributes |= OBJC_PR_copy;
+				break;
+			}
+			case 'R':
+			{
+				p.attributes |= OBJC_PR_readonly;
+				break;
+			}
+			case 'W':
+			{
+				p.attributes2 |= OBJC_PR_weak;
+				break;
 			}
 			case '&':
 			{
 				p.attributes |= OBJC_PR_retain;
+				break;
 			}
 			case 'N':
 			{
 				p.attributes |= OBJC_PR_nonatomic;
+				break;
+			}
+			case 'D':
+			{
+				p.attributes2 |= OBJC_PR_dynamic;
+				break;
 			}
 		}
 	}
@@ -460,13 +655,16 @@ BOOL class_addProperty(Class cls,
                        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; }
+	const char *iVarname = NULL;
+	struct objc_property p = propertyFromAttrs(attributes, attributeCount, &iVarname);
+	// If the iVar name is not the same as the name, then we need to construct
+	// the attributes string now, otherwise we can construct it lazily.
+	p.name = name;
+	constructPropertyAttributes(&p, iVarname);
 
 	struct objc_property_list *l = calloc(1, sizeof(struct objc_property_list)
 			+ sizeof(struct objc_property));
-	l->count = 0;
+	l->count = 1;
 	memcpy(&l->properties, &p, sizeof(struct objc_property));
 	LOCK_RUNTIME_FOR_SCOPE();
 	l->next = cls->properties;
@@ -486,12 +684,12 @@ void class_replaceProperty(Class cls,
 		class_addProperty(cls, name, attributes, attributeCount);
 		return;
 	}
-	struct objc_property p = propertyFromAttrs(attributes, attributeCount);
+	const char *iVarname = 0;
+	struct objc_property p = propertyFromAttrs(attributes, attributeCount, &iVarname);
+	p.name = name;
+	LOCK_RUNTIME_FOR_SCOPE();
+	constructPropertyAttributes(&p, iVarname);
 	memcpy(old, &p, sizeof(struct objc_property));
-	if (NULL == old->name)
-	{
-		old->name = name;
-	}
 }
 char *property_copyAttributeValue(objc_property_t property,
                                   const char *attributeName)
@@ -501,11 +699,17 @@ char *property_copyAttributeValue(objc_property_t property,
 	{
 		case 'T':
 		{
-			return strdup(property_getTypeEncoding(property));
+			const char *types = property_getTypeEncoding(property);
+			return (NULL == types) ? NULL : strdup(types);
+		}
+		case 'D':
+		{
+			return checkAttribute(property->attributes2, OBJC_PR_dynamic) &&
+			       !checkAttribute(property->attributes2, OBJC_PR_synthesized) ? strdup("") : 0;
 		}
 		case 'V':
 		{
-			return strdup(property_getName(property));
+			return strdup(property_getIVar(property));
 		}
 		case 'S':
 		{
@@ -515,17 +719,26 @@ char *property_copyAttributeValue(objc_property_t property,
 		{
 			return strdup(property->getter_name);
 		}
+		case 'R':
+		{
+			return checkAttribute(property->attributes, OBJC_PR_readonly) ? strdup("") : 0;
+		}
+		case 'W':
+		{
+			return checkAttribute(property->attributes2, OBJC_PR_weak) ? strdup("") : 0;
+		}
 		case 'C':
 		{
-			return ((property->attributes |= OBJC_PR_copy) == OBJC_PR_copy) ? strdup("") : 0;
+			return checkAttribute(property->attributes, OBJC_PR_copy) ? strdup("") : 0;
 		}
 		case '&':
 		{
-			return ((property->attributes |= OBJC_PR_retain) == OBJC_PR_retain) ? strdup("") : 0;
+			return checkAttribute(property->attributes, OBJC_PR_retain) ||
+			       checkAttribute(property->attributes2, OBJC_PR_strong) ? strdup("") : 0;
 		}
 		case 'N':
 		{
-			return ((property->attributes |= OBJC_PR_nonatomic) == OBJC_PR_nonatomic) ? strdup("") : 0;
+			return checkAttribute(property->attributes, OBJC_PR_nonatomic) ? strdup("") : 0;
 		}
 	}
 	return 0;
diff --git a/third_party/libobjc/protocol.c b/third_party/libobjc/protocol.c
index e9b80ce93c..63e5c92fea 100644
--- a/third_party/libobjc/protocol.c
+++ b/third_party/libobjc/protocol.c
@@ -11,7 +11,7 @@
 // Get the functions for string hashing
 #include "string_hash.h"
 
-static int protocol_compare(const char *name, 
+static int protocol_compare(const char *name,
                             const struct objc_protocol2 *protocol)
 {
 	return string_compare(name, protocol->name);
@@ -31,7 +31,7 @@ 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)
 {
@@ -47,10 +47,10 @@ static id ObjC2ProtocolClass = 0;
 
 static int isEmptyProtocol(struct objc_protocol2 *aProto)
 {
-	int isEmpty = 
-		((aProto->instance_methods == NULL) || 
+	int isEmpty =
+		((aProto->instance_methods == NULL) ||
 			(aProto->instance_methods->count == 0)) &&
-		((aProto->class_methods == NULL) || 
+		((aProto->class_methods == NULL) ||
 			(aProto->class_methods->count == 0)) &&
 		((aProto->protocol_list == NULL) ||
 		  (aProto->protocol_list->count == 0));
@@ -67,7 +67,7 @@ static int isEmptyProtocol(struct objc_protocol2 *aProto)
 
 // FIXME: Make p1 adopt all of the stuff in p2
 static void makeProtocolEqualToProtocol(struct objc_protocol2 *p1,
-                                        struct objc_protocol2 *p2) 
+                                        struct objc_protocol2 *p2)
 {
 #define COPY(x) p1->x = p2->x
 	COPY(instance_methods);
@@ -90,7 +90,7 @@ static struct objc_protocol2 *unique_protocol(struct objc_protocol2 *aProto)
 	{
 		ObjC2ProtocolClass = objc_getClass("Protocol2");
 	}
-	struct objc_protocol2 *oldProtocol = 
+	struct objc_protocol2 *oldProtocol =
 		protocol_for_name(aProto->name);
 	if (NULL == oldProtocol)
 	{
@@ -166,7 +166,7 @@ static BOOL init_protocols(struct objc_protocol_list *protocols)
 
 		// 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 version =
 			(enum protocol_version)(uintptr_t)aProto->isa;
 		switch (version)
 		{
@@ -309,17 +309,16 @@ get_method_list(Protocol *p,
 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 = 
+	if ((NULL == p) || (NULL == count)){ 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++)
+	struct objc_method_description *out =
+		calloc(sizeof(struct objc_method_description), list->count);
+	for (int i=0 ; i < (list->count) ; i++)
 	{
 		out[i].name = sel_registerTypedName_np(list->methods[i].name,
 		                                       list->methods[i].types);
@@ -403,14 +402,14 @@ objc_property_t protocol_getProperty(Protocol *protocol,
 		return NULL;
 	}
 	Protocol2 *p = (Protocol2*)protocol;
-	struct objc_property_list *properties = 
+	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)
+			if (strcmp(property_getName(prop), name) == 0)
 			{
 				return prop;
 			}
@@ -421,20 +420,20 @@ objc_property_t protocol_getProperty(Protocol *protocol,
 }
 
 
-struct objc_method_description 
+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 = 
+	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 
+	// 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);
@@ -464,7 +463,7 @@ BOOL protocol_isEqual(Protocol *p, Protocol *other)
 	{
 		return NO;
 	}
-	if (p == other || 
+	if (p == other ||
 		p->name == other->name ||
 		0 == strcmp(p->name, other->name))
 	{
@@ -609,8 +608,10 @@ void protocol_addProperty(Protocol *aProtocol,
 	}
 	struct objc_property_list *list = *listPtr;
 	int index = list->count-1;
-	struct objc_property p = propertyFromAttrs(attributes, attributeCount);
-	p.name = strdup(name);
+	const char *iVarName = NULL;
+	struct objc_property p = propertyFromAttrs(attributes, attributeCount, &iVarName);
+	p.name = name;
+	constructPropertyAttributes(&p, iVarName);
 	memcpy(&(list->properties[index]), &p, sizeof(p));
 }
 
diff --git a/third_party/libobjc/runtime.c b/third_party/libobjc/runtime.c
index 627be9a237..d0db7138cf 100644
--- a/third_party/libobjc/runtime.c
+++ b/third_party/libobjc/runtime.c
@@ -52,7 +52,7 @@ 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");
+		cxx_construct = sel_registerName(".cxx_construct");
 	}
 	struct objc_slot *slot = objc_get_slot(cls, cxx_construct);
 	if (NULL != slot)
@@ -570,7 +570,7 @@ IMP method_setImplementation(Method method, IMP imp)
 {
 	if (NULL == method) { return (IMP)NULL; }
 	IMP old = (IMP)method->imp;
-	method->imp = old;
+	method->imp = imp;
 	objc_updateDtableForClassContainingMethod(method);
 	return old;
 }
@@ -698,6 +698,8 @@ Class objc_allocateClassPair(Class superclass, const char *name, size_t extraByt
 		// Initialize the metaclass
 		// Set the meta-metaclass pointer to the name.  The runtime will fix this
 		// in objc_resolve_class().
+		// If the superclass is not yet resolved, then we need to look it up
+		// via the class table.
 		metaClass->isa = (Class)superclass->isa->isa->name;
 		metaClass->super_class = superclass->isa;
 	}
@@ -778,9 +780,12 @@ const char *object_getClassName(id obj)
 	return class_getName(object_getClass(obj));
 }
 
+PRIVATE void objc_resolve_class(Class);
+
 void objc_registerClassPair(Class cls)
 {
 	LOCK_RUNTIME_FOR_SCOPE();
 	class_table_insert(cls);
+	objc_resolve_class(cls);
 }
 
diff --git a/third_party/libobjc/sarray2.c b/third_party/libobjc/sarray2.c
index b9ca967fa6..c3c79d8f4a 100644
--- a/third_party/libobjc/sarray2.c
+++ b/third_party/libobjc/sarray2.c
@@ -8,6 +8,12 @@
 
 static void *EmptyArrayData[256];
 static SparseArray EmptyArray = { 0xff, 0, 0, (void**)&EmptyArrayData};
+static void *EmptyArrayData8[256] = { [0 ... 255] = &EmptyArray };
+static SparseArray EmptyArray8 = { 0xff00, 8, 0, (void**)&EmptyArrayData8};
+static void *EmptyArrayData16[256] = { [0 ... 255] = &EmptyArray8 };
+static SparseArray EmptyArray16 = { 0xff0000, 16, 0, (void**)&EmptyArrayData16};
+static void *EmptyArrayData24[256] = { [0 ... 255] = &EmptyArray16 };
+static SparseArray EmptyArray24 = { 0xff0000, 24, 0, (void**)&EmptyArrayData24};
 
 #define MAX_INDEX(sarray) (sarray->mask >> sarray->shift)
 #define DATA_SIZE(sarray) ((sarray->mask >> sarray->shift) + 1)
@@ -17,17 +23,35 @@ static SparseArray EmptyArray = { 0xff, 0, 0, (void**)&EmptyArrayData};
 #define base_shift 8
 #define base_mask ((1<<base_shift) - 1)
 
+void *EmptyChildForShift(uint32_t shift)
+{
+	switch(shift)
+	{
+		default: UNREACHABLE("Broken sparse array");
+		case 8:
+			return &EmptyArray;
+		case 16:
+			return &EmptyArray8;
+		case 24:
+			return &EmptyArray16;
+		case 32:
+			return &EmptyArray24;
+	}
+}
+
 static void init_pointers(SparseArray * sarray)
 {
 	sarray->data = calloc(DATA_SIZE(sarray), sizeof(void*));
 	if(sarray->shift != 0)
 	{
+		void *data = EmptyChildForShift(sarray->shift);
 		for(unsigned i=0 ; i<=MAX_INDEX(sarray) ; i++)
 		{
-			sarray->data[i] = &EmptyArray;
+			sarray->data[i] = data;
 		}
 	}
 }
+
 PRIVATE SparseArray * SparseArrayNewWithDepth(uint32_t depth)
 {
 	SparseArray * sarray = calloc(1, sizeof(SparseArray));
@@ -42,8 +66,13 @@ PRIVATE SparseArray *SparseArrayNew()
 {
 	return SparseArrayNewWithDepth(32);
 }
-PRIVATE SparseArray *SparseArrayExpandingArray(SparseArray *sarray)
+PRIVATE SparseArray *SparseArrayExpandingArray(SparseArray *sarray, uint32_t new_depth)
 {
+	if (new_depth == sarray->shift)
+	{
+		return sarray;
+	}
+	assert(new_depth > sarray->shift);
 	// Expanding a child sarray has undefined results.
 	assert(sarray->refCount == 1);
 	SparseArray *new = calloc(1, sizeof(SparseArray));
@@ -51,12 +80,12 @@ PRIVATE SparseArray *SparseArrayExpandingArray(SparseArray *sarray)
 	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++)
+	void *data = EmptyChildForShift(new->shift + 8);
+	for(unsigned i=1 ; i<=MAX_INDEX(sarray) ; i++)
 	{
-		newData[i] = &EmptyArray;
+		newData[i] = data;
 	}
 	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
@@ -65,7 +94,7 @@ PRIVATE SparseArray *SparseArrayExpandingArray(SparseArray *sarray)
 	sarray->shift += base_shift;
 	// Finally, set the mask to the correct value.  Now all lookups should work.
 	sarray->mask <<= base_shift;
-	return new;
+	return sarray;
 }
 
 static void *SparseArrayFind(SparseArray * sarray, uint32_t * index)
@@ -86,27 +115,34 @@ static void *SparseArrayFind(SparseArray * sarray, uint32_t * index)
 	}
 	else while (j<max)
 	{
+		// If the shift is not 0, then we need to recursively look at child
+		// nodes.
 		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
+			SparseArray *child = sarray->data[j];
+			// Skip over known-empty children
+			if ((&EmptyArray == child) ||
+			    (&EmptyArray8 == child) ||
+			    (&EmptyArray16 == child) ||
+			    (&EmptyArray24 == child))
 			{
 				//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;
 			}
+			else
+			{
+				// The recursive call will set index to the correct value for
+				// the next index, but won't update j
+				void * ret = SparseArrayFind(child, index);
+				if (ret != SARRAY_EMPTY)
+				{
+					return ret;
+				}
+			}
 			//Go to the next child
 			j++;
 		}
@@ -126,7 +162,10 @@ PRIVATE void SparseArrayInsert(SparseArray * sarray, uint32_t index, void *value
 	{
 		uint32_t i = MASK_INDEX(index);
 		SparseArray *child = sarray->data[i];
-		if(&EmptyArray == child)
+		if ((&EmptyArray == child) ||
+		    (&EmptyArray8 == child) ||
+		    (&EmptyArray16 == child) ||
+		    (&EmptyArray24 == child))
 		{
 			// Insert missing nodes
 			SparseArray * newsarray = calloc(1, sizeof(SparseArray));
@@ -185,6 +224,8 @@ PRIVATE void SparseArrayDestroy(SparseArray * sarray)
 {
 	// Don't really delete this sarray if its ref count is > 0
 	if (sarray == &EmptyArray || 
+	    sarray == &EmptyArray8 || 
+	    sarray == &EmptyArray16 || 
 		(__sync_sub_and_fetch(&sarray->refCount, 1) > 0))
  	{
 		return;
@@ -202,3 +243,24 @@ PRIVATE void SparseArrayDestroy(SparseArray * sarray)
 	free(sarray);
 }
 
+PRIVATE int SparseArraySize(SparseArray *sarray)
+{
+	int size = 0;
+	if (sarray->shift == 0)
+	{
+		return 256*sizeof(void*) + sizeof(SparseArray);
+	}
+	size += 256*sizeof(void*) + sizeof(SparseArray);
+	for(unsigned i=0 ; i<=MAX_INDEX(sarray) ; i++)
+	{
+		SparseArray *child = sarray->data[i];
+		if (child == &EmptyArray || 
+		    child == &EmptyArray8 || 
+		    child == &EmptyArray16)
+		{
+			continue;
+		}
+		size += SparseArraySize(child);
+	}
+	return size;
+}
diff --git a/third_party/libobjc/sarray2.h b/third_party/libobjc/sarray2.h
index ce1d41a850..cefc521574 100644
--- a/third_party/libobjc/sarray2.h
+++ b/third_party/libobjc/sarray2.h
@@ -112,7 +112,7 @@ 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);
+SparseArray *SparseArrayExpandingArray(SparseArray *sarray, uint32_t new_depth);
 /**
  * Insert a value at the specified index.
  */
@@ -136,4 +136,9 @@ void * SparseArrayNext(SparseArray * sarray, uint32_t * index);
  */
 SparseArray *SparseArrayCopy(SparseArray * sarray);
 
+/**
+ * Returns the total memory usage of a sparse array.  
+ */
+int SparseArraySize(SparseArray *sarray);
+
 #endif //_SARRAY_H_INCLUDED_
diff --git a/third_party/libobjc/selector_table.c b/third_party/libobjc/selector_table.c
index d75e1c494c..13b6ca5278 100644
--- a/third_party/libobjc/selector_table.c
+++ b/third_party/libobjc/selector_table.c
@@ -22,7 +22,6 @@
 #	define TDD(x)
 #endif
 
-#define fprintf(...)
 
 
 // Define the pool allocator for selectors.  This is a simple bump-the-pointer
@@ -43,6 +42,12 @@ static uint32_t selector_count = 1;
  */
 PRIVATE SparseArray *selector_list  = NULL;
 
+#ifdef DEBUG_SELECTOR_TABLE
+#define DEBUG_LOG(...) fprintf(stderr, __VA_ARGS__)
+#else
+#define DEBUG_LOG(...)
+#endif
+
 // Get the functions for string hashing
 #include "string_hash.h"
 
@@ -156,7 +161,7 @@ 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));
+	DEBUG_LOG("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));
 }
@@ -211,6 +216,7 @@ static inline uint32_t hash_selector(const void *s)
 }
 
 #define MAP_TABLE_NAME selector
+#define MAP_TABLE_SINGLE_THREAD
 #define MAP_TABLE_COMPARE_FUNCTION selector_identical
 #define MAP_TABLE_HASH_KEY hash_selector
 #define MAP_TABLE_HASH_VALUE hash_selector
@@ -225,6 +231,20 @@ static selector_table *sel_table;
  */
 mutex_t selector_table_lock;
 
+static int selector_name_copies;
+
+PRIVATE void log_selector_memory_usage(void)
+{
+	fprintf(stderr, "%d bytes in selector name list.\n", SparseArraySize(selector_list));
+	fprintf(stderr, "%d bytes in selector names.\n", selector_name_copies);
+	fprintf(stderr, "%d bytes (%d entries) in selector hash table.\n", (int)(sel_table->table_size *
+	        sizeof(struct selector_table_cell_struct)), sel_table->table_size);
+	fprintf(stderr, "%d selectors registered.\n", selector_count);
+	fprintf(stderr, "%d hash table cells per selector (%.2f%% full)\n", sel_table->table_size / selector_count,  ((float)selector_count) /  sel_table->table_size * 100);
+}
+
+
+
 
 /**
  * Resizes the dtables to ensure that they can store as many selectors as
@@ -245,11 +265,12 @@ PRIVATE void init_selector_tables()
 static SEL selector_lookup(const char *name, const char *types)
 {
 	struct objc_selector sel = {{name}, types};
+	LOCK_FOR_SCOPE(&selector_table_lock);
 	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));
+	DEBUG_LOG("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;
@@ -269,7 +290,7 @@ 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));
+		DEBUG_LOG("Registering selector %d %s\n", (int)idx, sel_getNameNonUnique(aSel));
 		add_selector_to_table(aSel, idx, idx);
 		objc_resize_dtables(selector_count);
 		return;
@@ -281,7 +302,7 @@ static inline void register_selector_locked(SEL aSel)
 		untyped = selector_pool_alloc();
 		untyped->name = aSel->name;
 		untyped->types = 0;
-		fprintf(stderr, "Registering selector %d %s\n", (int)idx, sel_getNameNonUnique(aSel));
+		DEBUG_LOG("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
@@ -294,7 +315,7 @@ static inline void register_selector_locked(SEL aSel)
 	}
 	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));
+	DEBUG_LOG("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.
@@ -338,10 +359,10 @@ 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)));
+	DEBUG_LOG("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");
+		DEBUG_LOG("Not adding new copy\n");
 		return copy;
 	}
 	LOCK_FOR_SCOPE(&selector_table_lock);
@@ -352,9 +373,26 @@ static SEL objc_register_selector_copy(SEL aSel, BOOL copyArgs)
 	}
 	// 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);
+	copy->name = aSel->name;
+	copy->types = (NULL == aSel->types) ? NULL : aSel->types;
+	if (copyArgs)
+	{
+		SEL untyped = selector_lookup(aSel->name, 0);
+		if (untyped != NULL)
+		{
+			copy->name = sel_getName(untyped);
+		}
+		else
+		{
+			copy->name = strdup(aSel->name);
+			selector_name_copies += strlen(copy->name);
+		}
+		if (copy->types != NULL)
+		{
+			copy->types = strdup(copy->types);
+			selector_name_copies += strlen(copy->types);
+		}
+	}
 	// Try to register the copy as the authoritative version
 	register_selector_locked(copy);
 	return copy;
diff --git a/third_party/libobjc/spinlock.h b/third_party/libobjc/spinlock.h
index f3dc2cfb29..e65e60815f 100644
--- a/third_party/libobjc/spinlock.h
+++ b/third_party/libobjc/spinlock.h
@@ -26,7 +26,7 @@ extern int spinlocks[spinlock_count];
  * 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)
+static inline volatile int *lock_for_pointer(const void *ptr)
 {
 	intptr_t hash = (intptr_t)ptr;
 	// Most properties will be pointers, so disregard the lowest few bits
diff --git a/third_party/libobjc/unwind-arm.h b/third_party/libobjc/unwind-arm.h
index 63774611ca..385abab171 100644
--- a/third_party/libobjc/unwind-arm.h
+++ b/third_party/libobjc/unwind-arm.h
@@ -25,6 +25,8 @@ static const _Unwind_State _US_UNWIND_FRAME_RESUME   = 2;
 #	define _US_UNWIND_FRAME_RESUME 2
 #endif
 
+typedef int _Unwind_Action;
+
 typedef struct _Unwind_Context _Unwind_Context;
 
 typedef uint32_t _Unwind_EHT_Header;
-- 
GitLab