Index: CMakeLists.txt
===================================================================
--- CMakeLists.txt
+++ CMakeLists.txt
@@ -63,6 +63,7 @@
   ${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/http.go
   ${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/list.go
   ${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/main.go
+  ${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/note.go
   ${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/pkg.go
   ${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/run.go
   ${CMAKE_CURRENT_SOURCE_DIR}/third_party/gofrontend/libgo/go/cmd/go/signal.go
@@ -78,6 +79,7 @@
 
 add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/bin/llgo-go${CMAKE_EXECUTABLE_SUFFIX}
   COMMAND ${CMAKE_BINARY_DIR}/bin/llgo -static-libgo
+          -I ${CMAKE_CURRENT_BINARY_DIR}/libgo
           -o ${CMAKE_BINARY_DIR}/bin/llgo-go${CMAKE_EXECUTABLE_SUFFIX}
           ${LLGO_GO_SOURCES}
           ${CMAKE_CURRENT_BINARY_DIR}/libgo/zstdpkglist.go
Index: cmd/gllgo/gllgo.go
===================================================================
--- cmd/gllgo/gllgo.go
+++ cmd/gllgo/gllgo.go
@@ -746,7 +746,7 @@
 			if opts.staticLibgo {
 				args = append(args, "-Wl,-Bstatic", "-lgo-llgo", "-Wl,-Bdynamic", "-lpthread", "-lm")
 			} else {
-				args = append(args, "-lgo-llgo")
+				args = append(args, "-lgo-llgo", "-lm")
 			}
 		} else {
 			linkerPath = opts.gccgoPath
Index: irgen/runtime.go
===================================================================
--- irgen/runtime.go
+++ irgen/runtime.go
@@ -64,6 +64,7 @@
 	// Runtime intrinsics
 	append,
 	assertInterface,
+	byteArrayToString,
 	canRecover,
 	chanCap,
 	chanLen,
@@ -92,7 +93,6 @@
 	New,
 	newChannel,
 	newMap,
-	NewNopointers,
 	newSelect,
 	panic,
 	printBool,
@@ -121,6 +121,7 @@
 	stringiter2,
 	stringPlus,
 	stringSlice,
+	stringToByteArray,
 	stringToIntArray,
 	typeDescriptorsEqual,
 	undefer runtimeFnInfo
@@ -141,6 +142,7 @@
 	UnsafePointer := types.Typ[types.UnsafePointer]
 
 	EmptyInterface := types.NewInterface(nil, nil)
+	ByteSlice := types.NewSlice(types.Typ[types.Byte])
 	IntSlice := types.NewSlice(types.Typ[types.Int])
 
 	for _, rt := range [...]struct {
@@ -162,6 +164,13 @@
 			res:  []types.Type{UnsafePointer},
 		},
 		{
+			name:  "__go_byte_array_to_string",
+			rfi:   &ri.byteArrayToString,
+			args:  []types.Type{UnsafePointer, Int},
+			res:   []types.Type{String},
+			attrs: []llvm.Attribute{llvm.NoUnwindAttribute},
+		},
+		{
 			name: "__go_can_recover",
 			rfi:  &ri.canRecover,
 			args: []types.Type{UnsafePointer},
@@ -301,10 +310,11 @@
 			res:  []types.Type{Int},
 		},
 		{
-			name: "__go_new",
-			rfi:  &ri.New,
-			args: []types.Type{UnsafePointer, Uintptr},
-			res:  []types.Type{UnsafePointer},
+			name:  "__go_new",
+			rfi:   &ri.New,
+			args:  []types.Type{UnsafePointer, Uintptr},
+			res:   []types.Type{UnsafePointer},
+			attrs: []llvm.Attribute{llvm.NoUnwindAttribute},
 		},
 		{
 			name: "__go_new_channel",
@@ -319,12 +329,6 @@
 			res:  []types.Type{UnsafePointer},
 		},
 		{
-			name: "__go_new_nopointers",
-			rfi:  &ri.NewNopointers,
-			args: []types.Type{UnsafePointer, Uintptr},
-			res:  []types.Type{UnsafePointer},
-		},
-		{
 			name: "runtime.newselect",
 			rfi:  &ri.newSelect,
 			args: []types.Type{Int32},
@@ -466,6 +470,13 @@
 			res:  []types.Type{String},
 		},
 		{
+			name:  "__go_string_to_byte_array",
+			rfi:   &ri.stringToByteArray,
+			args:  []types.Type{String},
+			res:   []types.Type{ByteSlice},
+			attrs: []llvm.Attribute{llvm.NoUnwindAttribute},
+		},
+		{
 			name: "__go_string_to_int_array",
 			rfi:  &ri.stringToIntArray,
 			args: []types.Type{String},
@@ -563,12 +574,6 @@
 	return v
 }
 
-func (fr *frame) createMalloc(size llvm.Value) llvm.Value {
-	return fr.runtime.NewNopointers.callOnly(fr,
-		llvm.ConstNull(llvm.PointerType(llvm.Int8Type(), 0)),
-		fr.createZExtOrTrunc(size, fr.target.IntPtrType(), ""))[0]
-}
-
 func (fr *frame) createTypeMalloc(t types.Type) llvm.Value {
 	size := llvm.ConstInt(fr.target.IntPtrType(), uint64(fr.llvmtypes.Sizeof(t)), false)
 	malloc := fr.runtime.New.callOnly(fr, fr.types.ToRuntime(t), size)[0]
Index: irgen/ssa.go
===================================================================
--- irgen/ssa.go
+++ irgen/ssa.go
@@ -402,7 +402,7 @@
 	// an unwind block. We can short-circuit the check for defers with
 	// f.Recover != nil.
 	if f.Recover != nil || hasDefer(f) {
-		fr.unwindBlock = llvm.AddBasicBlock(fr.function, "")
+		fr.unwindBlock = llvm.AddBasicBlock(fr.function, "unwind")
 		fr.frameptr = fr.builder.CreateAlloca(llvm.Int8Type(), "")
 	}
 
@@ -432,7 +432,7 @@
 	fr.fixupPhis()
 
 	if !fr.unwindBlock.IsNil() {
-		fr.setupUnwindBlock(f.Recover, f.Signature.Results())
+		fr.setupUnwindBlock(f.Recover)
 	}
 
 	// The init function needs to register the GC roots first. We do this
@@ -623,19 +623,12 @@
 	fr.runtime.undefer.invoke(fr, retrylpad, fr.frameptr)
 }
 
-func (fr *frame) setupUnwindBlock(rec *ssa.BasicBlock, results *types.Tuple) {
-	recoverbb := llvm.AddBasicBlock(fr.function, "")
+func (fr *frame) setupUnwindBlock(rec *ssa.BasicBlock) {
+	var recoverbb llvm.BasicBlock
 	if rec != nil {
-		fr.translateBlock(rec, recoverbb)
-	} else if results.Len() == 0 || results.At(0).Anonymous() {
-		// TODO(pcc): Remove this code after https://codereview.appspot.com/87210044/ lands
-		fr.builder.SetInsertPointAtEnd(recoverbb)
-		values := make([]llvm.Value, results.Len())
-		for i := range values {
-			values[i] = llvm.ConstNull(fr.llvmtypes.ToLLVM(results.At(i).Type()))
-		}
-		fr.retInf.encode(llvm.GlobalContext(), fr.allocaBuilder, fr.builder, values)
+		recoverbb = fr.blocks[rec.Index]
 	} else {
+		recoverbb = llvm.AddBasicBlock(fr.function, "recover")
 		fr.builder.SetInsertPointAtEnd(recoverbb)
 		fr.builder.CreateUnreachable()
 	}
Index: irgen/typemap.go
===================================================================
--- irgen/typemap.go
+++ irgen/typemap.go
@@ -71,13 +71,25 @@
 
 	typeSliceType, methodSliceType, imethodSliceType, structFieldSliceType llvm.Type
 
-	hashFnType, equalFnType llvm.Type
-
-	hashFnEmptyInterface, hashFnInterface, hashFnFloat, hashFnComplex, hashFnString, hashFnIdentity, hashFnError        llvm.Value
-	equalFnEmptyInterface, equalFnInterface, equalFnFloat, equalFnComplex, equalFnString, equalFnIdentity, equalFnError llvm.Value
-
-	zeroType  llvm.Type
-	zeroValue llvm.Value
+	funcValType                           llvm.Type
+	hashFnType, equalFnType               llvm.Type
+	ptrHashFnNestType, ptrEqualFnNestType llvm.Type // with *funcValType as first arg
+
+	hashFnEmptyInterfaceDescriptor,
+	hashFnInterfaceDescriptor,
+	hashFnFloatDescriptor,
+	hashFnComplexDescriptor,
+	hashFnStringDescriptor,
+	hashFnIdentityDescriptor,
+	hashFnErrorDescriptor llvm.Value
+
+	equalFnEmptyInterfaceDescriptor,
+	equalFnInterfaceDescriptor,
+	equalFnFloatDescriptor,
+	equalFnComplexDescriptor,
+	equalFnStringDescriptor,
+	equalFnIdentityDescriptor,
+	equalFnErrorDescriptor llvm.Value
 }
 
 func NewLLVMTypeMap(ctx llvm.Context, target llvm.TargetData) *llvmTypeMap {
@@ -117,35 +129,60 @@
 	boolType := llvm.Int8Type()
 	stringPtrType := llvm.PointerType(tm.stringType, 0)
 
-	// Create runtime algorithm function types.
+	tm.funcValType = tm.ctx.StructCreateNamed("funcVal")
+	tm.funcValType.StructSetBody([]llvm.Type{
+		llvm.PointerType(llvm.FunctionType(llvm.VoidType(), []llvm.Type{}, false), 0),
+	}, false)
+	ptrFuncValType := llvm.PointerType(tm.funcValType, 0)
+
 	params := []llvm.Type{voidPtrType, uintptrType}
 	tm.hashFnType = llvm.FunctionType(uintptrType, params, false)
+	params = []llvm.Type{ptrFuncValType, voidPtrType, uintptrType}
+	tm.ptrHashFnNestType = llvm.PointerType(llvm.FunctionType(uintptrType, params, false), 0)
 	params = []llvm.Type{voidPtrType, voidPtrType, uintptrType}
 	tm.equalFnType = llvm.FunctionType(boolType, params, false)
+	params = []llvm.Type{ptrFuncValType, voidPtrType, voidPtrType, uintptrType}
+	tm.ptrEqualFnNestType = llvm.PointerType(llvm.FunctionType(boolType, params, false), 0)
 
-	tm.hashFnEmptyInterface = llvm.AddFunction(tm.module, "__go_type_hash_empty_interface", tm.hashFnType)
-	tm.hashFnInterface = llvm.AddFunction(tm.module, "__go_type_hash_interface", tm.hashFnType)
-	tm.hashFnFloat = llvm.AddFunction(tm.module, "__go_type_hash_float", tm.hashFnType)
-	tm.hashFnComplex = llvm.AddFunction(tm.module, "__go_type_hash_complex", tm.hashFnType)
-	tm.hashFnString = llvm.AddFunction(tm.module, "__go_type_hash_string", tm.hashFnType)
-	tm.hashFnIdentity = llvm.AddFunction(tm.module, "__go_type_hash_identity", tm.hashFnType)
-	tm.hashFnError = llvm.AddFunction(tm.module, "__go_type_hash_error", tm.hashFnType)
-
-	tm.equalFnEmptyInterface = llvm.AddFunction(tm.module, "__go_type_equal_empty_interface", tm.equalFnType)
-	tm.equalFnInterface = llvm.AddFunction(tm.module, "__go_type_equal_interface", tm.equalFnType)
-	tm.equalFnFloat = llvm.AddFunction(tm.module, "__go_type_equal_float", tm.equalFnType)
-	tm.equalFnComplex = llvm.AddFunction(tm.module, "__go_type_equal_complex", tm.equalFnType)
-	tm.equalFnString = llvm.AddFunction(tm.module, "__go_type_equal_string", tm.equalFnType)
-	tm.equalFnIdentity = llvm.AddFunction(tm.module, "__go_type_equal_identity", tm.equalFnType)
-	tm.equalFnError = llvm.AddFunction(tm.module, "__go_type_equal_error", tm.equalFnType)
-
-	// The body of this type is set in emitTypeDescInitializers once we have scanned
-	// every type, as it needs to be as large and well aligned as the
-	// largest/most aligned type.
-	tm.zeroType = tm.ctx.StructCreateNamed("zero")
-	tm.zeroValue = llvm.AddGlobal(tm.module, tm.zeroType, "go$zerovalue")
-	tm.zeroValue.SetLinkage(llvm.CommonLinkage)
-	tm.zeroValue.SetInitializer(llvm.ConstNull(tm.zeroType))
+	algorithmDescriptors := [...]struct {
+		Name  string
+		Hash  *llvm.Value
+		Equal *llvm.Value
+	}{{
+		"empty_interface",
+		&tm.hashFnEmptyInterfaceDescriptor,
+		&tm.equalFnEmptyInterfaceDescriptor,
+	}, {
+		"interface",
+		&tm.hashFnInterfaceDescriptor,
+		&tm.equalFnInterfaceDescriptor,
+	}, {
+		"float",
+		&tm.hashFnFloatDescriptor,
+		&tm.equalFnFloatDescriptor,
+	}, {
+		"complex",
+		&tm.hashFnComplexDescriptor,
+		&tm.equalFnComplexDescriptor,
+	}, {
+		"string",
+		&tm.hashFnStringDescriptor,
+		&tm.equalFnStringDescriptor,
+	}, {
+		"identity",
+		&tm.hashFnIdentityDescriptor,
+		&tm.equalFnIdentityDescriptor,
+	}, {
+		"error",
+		&tm.hashFnErrorDescriptor,
+		&tm.equalFnErrorDescriptor,
+	}}
+	for _, alg := range algorithmDescriptors {
+		hashDescriptorName := "__go_type_hash_" + alg.Name + "_descriptor"
+		equalDescriptorName := "__go_type_equal_" + alg.Name + "_descriptor"
+		*alg.Hash = llvm.AddGlobal(tm.module, tm.funcValType, hashDescriptorName)
+		*alg.Equal = llvm.AddGlobal(tm.module, tm.funcValType, equalDescriptorName)
+	}
 
 	tm.commonTypeType = tm.ctx.StructCreateNamed("commonType")
 	commonTypeTypePtr := llvm.PointerType(tm.commonTypeType, 0)
@@ -174,13 +211,12 @@
 		tm.ctx.Int8Type(),                        // fieldAlign
 		uintptrType,                              // size
 		tm.ctx.Int32Type(),                       // hash
-		llvm.PointerType(tm.hashFnType, 0),       // hashfn
-		llvm.PointerType(tm.equalFnType, 0),      // equalfn
+		llvm.PointerType(tm.funcValType, 0),      // hashfn
+		llvm.PointerType(tm.funcValType, 0),      // equalfn
 		voidPtrType,                              // gc
 		stringPtrType,                            // string
 		llvm.PointerType(tm.uncommonTypeType, 0), // uncommonType
 		commonTypeTypePtr,                        // ptrToThis
-		llvm.PointerType(tm.zeroType, 0),         // zero
 	}, false)
 
 	tm.typeSliceType = tm.makeNamedSliceType("typeSlice", commonTypeTypePtr)
@@ -1096,9 +1132,6 @@
 			}
 		}
 	}
-
-	tm.zeroType.StructSetBody([]llvm.Type{llvm.ArrayType(tm.ctx.Int8Type(), int(maxSize))}, false)
-	tm.zeroValue.SetAlignment(int(maxAlign))
 }
 
 const (
@@ -1247,8 +1280,8 @@
 	equals := make([]llvm.Value, st.NumFields())
 
 	for i := range hashes {
-		fhash, fequal := tm.getAlgorithmFunctions(st.Field(i).Type())
-		if fhash == tm.hashFnError {
+		fhash, fequal := tm.getAlgorithmDescriptors(st.Field(i).Type())
+		if fhash == tm.hashFnErrorDescriptor {
 			return fhash, fequal
 		}
 		hashes[i], equals[i] = fhash, fequal
@@ -1260,53 +1293,52 @@
 	builder := tm.ctx.NewBuilder()
 	defer builder.Dispose()
 
-	hash = llvm.AddFunction(tm.module, tm.mc.mangleHashFunctionName(st), tm.hashFnType)
-	hash.SetLinkage(llvm.LinkOnceODRLinkage)
-	builder.SetInsertPointAtEnd(llvm.AddBasicBlock(hash, "entry"))
-	sptr := builder.CreateBitCast(hash.Param(0), llsptrty, "")
+	hashFunctionName := tm.mc.mangleHashFunctionName(st)
+	hashFn := llvm.AddFunction(tm.module, hashFunctionName, tm.hashFnType)
+	hashFn.SetLinkage(llvm.LinkOnceODRLinkage)
+	hash = tm.createAlgorithmDescriptor(hashFunctionName+"_descriptor", hashFn)
+
+	builder.SetInsertPointAtEnd(llvm.AddBasicBlock(hashFn, "entry"))
+	sptr := builder.CreateBitCast(hashFn.Param(0), llsptrty, "")
 
 	hashval := llvm.ConstNull(tm.inttype)
 	i33 := llvm.ConstInt(tm.inttype, 33, false)
 
-	for i, fhash := range hashes {
+	for i, hashDescriptor := range hashes {
 		fptr := builder.CreateStructGEP(sptr, i, "")
 		fptr = builder.CreateBitCast(fptr, i8ptr, "")
-
 		fsize := llvm.ConstInt(tm.inttype, uint64(tm.sizes.Sizeof(st.Field(i).Type())), false)
-
-		hashcall := builder.CreateCall(fhash, []llvm.Value{fptr, fsize}, "")
+		fhash := tm.callHashDescriptor(builder, hashDescriptor, fptr, fsize)
 		hashval = builder.CreateMul(hashval, i33, "")
-		hashval = builder.CreateAdd(hashval, hashcall, "")
+		hashval = builder.CreateAdd(hashval, fhash, "")
 	}
 
 	builder.CreateRet(hashval)
 
-	equal = llvm.AddFunction(tm.module, tm.mc.mangleEqualFunctionName(st), tm.equalFnType)
-	equal.SetLinkage(llvm.LinkOnceODRLinkage)
-	eqentrybb := llvm.AddBasicBlock(equal, "entry")
-	eqretzerobb := llvm.AddBasicBlock(equal, "retzero")
+	equalFunctionName := tm.mc.mangleEqualFunctionName(st)
+	equalFn := llvm.AddFunction(tm.module, equalFunctionName, tm.equalFnType)
+	equalFn.SetLinkage(llvm.LinkOnceODRLinkage)
+	equal = tm.createAlgorithmDescriptor(equalFunctionName+"_descriptor", equalFn)
 
+	eqentrybb := llvm.AddBasicBlock(equalFn, "entry")
+	eqretzerobb := llvm.AddBasicBlock(equalFn, "retzero")
 	builder.SetInsertPointAtEnd(eqentrybb)
-	s1ptr := builder.CreateBitCast(equal.Param(0), llsptrty, "")
-	s2ptr := builder.CreateBitCast(equal.Param(1), llsptrty, "")
+	s1ptr := builder.CreateBitCast(equalFn.Param(0), llsptrty, "")
+	s2ptr := builder.CreateBitCast(equalFn.Param(1), llsptrty, "")
 
 	zerobool := llvm.ConstNull(tm.ctx.Int8Type())
 	onebool := llvm.ConstInt(tm.ctx.Int8Type(), 1, false)
 
-	for i, fequal := range equals {
+	for i, equalDescriptor := range equals {
 		f1ptr := builder.CreateStructGEP(s1ptr, i, "")
 		f1ptr = builder.CreateBitCast(f1ptr, i8ptr, "")
 		f2ptr := builder.CreateStructGEP(s2ptr, i, "")
 		f2ptr = builder.CreateBitCast(f2ptr, i8ptr, "")
-
 		fsize := llvm.ConstInt(tm.inttype, uint64(tm.sizes.Sizeof(st.Field(i).Type())), false)
-
-		equalcall := builder.CreateCall(fequal, []llvm.Value{f1ptr, f2ptr, fsize}, "")
-		equaleqzero := builder.CreateICmp(llvm.IntEQ, equalcall, zerobool, "")
-
-		contbb := llvm.AddBasicBlock(equal, "cont")
+		fequal := tm.callEqualDescriptor(builder, equalDescriptor, f1ptr, f2ptr, fsize)
+		equaleqzero := builder.CreateICmp(llvm.IntEQ, fequal, zerobool, "")
+		contbb := llvm.AddBasicBlock(equalFn, "cont")
 		builder.CreateCondBr(equaleqzero, eqretzerobb, contbb)
-
 		builder.SetInsertPointAtEnd(contbb)
 	}
 
@@ -1324,8 +1356,8 @@
 		return algs.hash, algs.equal
 	}
 
-	ehash, eequal := tm.getAlgorithmFunctions(at.Elem())
-	if ehash == tm.hashFnError {
+	ehash, eequal := tm.getAlgorithmDescriptors(at.Elem())
+	if ehash == tm.hashFnErrorDescriptor {
 		return ehash, eequal
 	}
 
@@ -1339,20 +1371,28 @@
 	builder := tm.ctx.NewBuilder()
 	defer builder.Dispose()
 
-	hash = llvm.AddFunction(tm.module, tm.mc.mangleHashFunctionName(at), tm.hashFnType)
-	hash.SetLinkage(llvm.LinkOnceODRLinkage)
-	hashentrybb := llvm.AddBasicBlock(hash, "entry")
+	hashFunctionName := tm.mc.mangleHashFunctionName(at)
+	hashFn := llvm.AddFunction(tm.module, hashFunctionName, tm.hashFnType)
+	hashFn.SetLinkage(llvm.LinkOnceODRLinkage)
+	hash = tm.createAlgorithmDescriptor(hashFunctionName+"_descriptor", hashFn)
+	equalFunctionName := tm.mc.mangleHashFunctionName(at)
+	equalFn := llvm.AddFunction(tm.module, equalFunctionName, tm.equalFnType)
+	equalFn.SetLinkage(llvm.LinkOnceODRLinkage)
+	equal = tm.createAlgorithmDescriptor(equalFunctionName+"_descriptor", equalFn)
+	tm.algs.Set(at, algorithmFns{hash, equal})
+
+	hashentrybb := llvm.AddBasicBlock(hashFn, "entry")
 	builder.SetInsertPointAtEnd(hashentrybb)
 	if at.Len() == 0 {
 		builder.CreateRet(llvm.ConstNull(tm.inttype))
 	} else {
 		i33 := llvm.ConstInt(tm.inttype, 33, false)
 
-		aptr := builder.CreateBitCast(hash.Param(0), llelemty, "")
-		loopbb := llvm.AddBasicBlock(hash, "loop")
+		aptr := builder.CreateBitCast(hashFn.Param(0), llelemty, "")
+		loopbb := llvm.AddBasicBlock(hashFn, "loop")
 		builder.CreateBr(loopbb)
 
-		exitbb := llvm.AddBasicBlock(hash, "exit")
+		exitbb := llvm.AddBasicBlock(hashFn, "exit")
 
 		builder.SetInsertPointAtEnd(loopbb)
 		indexphi := builder.CreatePHI(tm.inttype, "")
@@ -1363,7 +1403,7 @@
 		eptr := builder.CreateGEP(aptr, []llvm.Value{index}, "")
 		eptr = builder.CreateBitCast(eptr, i8ptr, "")
 
-		hashcall := builder.CreateCall(ehash, []llvm.Value{eptr, esize}, "")
+		hashcall := tm.callHashDescriptor(builder, ehash, eptr, esize)
 		hashval = builder.CreateMul(hashval, i33, "")
 		hashval = builder.CreateAdd(hashval, hashcall, "")
 
@@ -1388,20 +1428,18 @@
 	zerobool := llvm.ConstNull(tm.ctx.Int8Type())
 	onebool := llvm.ConstInt(tm.ctx.Int8Type(), 1, false)
 
-	equal = llvm.AddFunction(tm.module, tm.mc.mangleEqualFunctionName(at), tm.equalFnType)
-	equal.SetLinkage(llvm.LinkOnceODRLinkage)
-	eqentrybb := llvm.AddBasicBlock(equal, "entry")
+	eqentrybb := llvm.AddBasicBlock(equalFn, "entry")
 	builder.SetInsertPointAtEnd(eqentrybb)
 	if at.Len() == 0 {
 		builder.CreateRet(onebool)
 	} else {
-		a1ptr := builder.CreateBitCast(equal.Param(0), llelemty, "")
-		a2ptr := builder.CreateBitCast(equal.Param(1), llelemty, "")
-		loopbb := llvm.AddBasicBlock(equal, "loop")
+		a1ptr := builder.CreateBitCast(equalFn.Param(0), llelemty, "")
+		a2ptr := builder.CreateBitCast(equalFn.Param(1), llelemty, "")
+		loopbb := llvm.AddBasicBlock(equalFn, "loop")
 		builder.CreateBr(loopbb)
 
-		exitbb := llvm.AddBasicBlock(equal, "exit")
-		retzerobb := llvm.AddBasicBlock(equal, "retzero")
+		exitbb := llvm.AddBasicBlock(equalFn, "exit")
+		retzerobb := llvm.AddBasicBlock(equalFn, "retzero")
 
 		builder.SetInsertPointAtEnd(loopbb)
 		indexphi := builder.CreatePHI(tm.inttype, "")
@@ -1412,10 +1450,10 @@
 		e2ptr := builder.CreateGEP(a2ptr, []llvm.Value{index}, "")
 		e2ptr = builder.CreateBitCast(e2ptr, i8ptr, "")
 
-		equalcall := builder.CreateCall(eequal, []llvm.Value{e1ptr, e2ptr, esize}, "")
+		equalcall := tm.callEqualDescriptor(builder, eequal, e1ptr, e2ptr, esize)
 		equaleqzero := builder.CreateICmp(llvm.IntEQ, equalcall, zerobool, "")
 
-		contbb := llvm.AddBasicBlock(equal, "cont")
+		contbb := llvm.AddBasicBlock(equalFn, "cont")
 		builder.CreateCondBr(equaleqzero, retzerobb, contbb)
 
 		builder.SetInsertPointAtEnd(contbb)
@@ -1437,45 +1475,71 @@
 		builder.CreateRet(zerobool)
 	}
 
-	tm.algs.Set(at, algorithmFns{hash, equal})
 	return
 }
 
-func (tm *TypeMap) getAlgorithmFunctions(t types.Type) (hash, equal llvm.Value) {
+func (tm *TypeMap) createAlgorithmDescriptor(name string, fn llvm.Value) llvm.Value {
+	d := llvm.AddGlobal(tm.module, tm.funcValType, name)
+	d.SetLinkage(llvm.LinkOnceODRLinkage)
+	d.SetGlobalConstant(true)
+	fn = llvm.ConstBitCast(fn, tm.funcValType.StructElementTypes()[0])
+	init := llvm.ConstNull(tm.funcValType)
+	init = llvm.ConstInsertValue(init, fn, []uint32{0})
+	d.SetInitializer(init)
+	return d
+}
+
+func (tm *TypeMap) callHashDescriptor(builder llvm.Builder, descriptor, ptr, size llvm.Value) llvm.Value {
+	hashFn := builder.CreateLoad(builder.CreateStructGEP(descriptor, 0, ""), "")
+	hashFn = builder.CreateBitCast(hashFn, tm.ptrHashFnNestType, "")
+	hashcall := builder.CreateCall(hashFn, []llvm.Value{descriptor, ptr, size}, "")
+	hashcall.AddInstrAttribute(1, llvm.NestAttribute)
+	return hashcall
+}
+
+func (tm *TypeMap) callEqualDescriptor(builder llvm.Builder, descriptor, ptr1, ptr2, size llvm.Value) llvm.Value {
+	equalFn := builder.CreateLoad(builder.CreateStructGEP(descriptor, 0, ""), "")
+	equalFn = builder.CreateBitCast(equalFn, tm.ptrEqualFnNestType, "")
+	equalcall := builder.CreateCall(equalFn, []llvm.Value{descriptor, ptr1, ptr2, size}, "")
+	equalcall.AddInstrAttribute(1, llvm.NestAttribute)
+	return equalcall
+}
+
+func (tm *TypeMap) getAlgorithmDescriptors(t types.Type) (hash, equal llvm.Value) {
 	switch t := t.Underlying().(type) {
 	case *types.Interface:
 		if t.NumMethods() == 0 {
-			hash = tm.hashFnEmptyInterface
-			equal = tm.equalFnEmptyInterface
+			hash = tm.hashFnEmptyInterfaceDescriptor
+			equal = tm.equalFnEmptyInterfaceDescriptor
 		} else {
-			hash = tm.hashFnInterface
-			equal = tm.equalFnInterface
+			hash = tm.hashFnInterfaceDescriptor
+			equal = tm.equalFnInterfaceDescriptor
 		}
 	case *types.Basic:
 		switch t.Kind() {
 		case types.Float32, types.Float64:
-			hash = tm.hashFnFloat
-			equal = tm.equalFnFloat
+			hash = tm.hashFnFloatDescriptor
+			equal = tm.equalFnFloatDescriptor
 		case types.Complex64, types.Complex128:
-			hash = tm.hashFnComplex
-			equal = tm.equalFnComplex
+			hash = tm.hashFnComplexDescriptor
+			equal = tm.equalFnComplexDescriptor
 		case types.String:
-			hash = tm.hashFnString
-			equal = tm.equalFnString
+			hash = tm.hashFnStringDescriptor
+			equal = tm.equalFnStringDescriptor
 		default:
-			hash = tm.hashFnIdentity
-			equal = tm.equalFnIdentity
+			hash = tm.hashFnIdentityDescriptor
+			equal = tm.equalFnIdentityDescriptor
 		}
 	case *types.Signature, *types.Map, *types.Slice:
-		hash = tm.hashFnError
-		equal = tm.equalFnError
+		hash = tm.hashFnErrorDescriptor
+		equal = tm.equalFnErrorDescriptor
 	case *types.Struct:
 		hash, equal = tm.getStructAlgorithmFunctions(t)
 	case *types.Array:
 		hash, equal = tm.getArrayAlgorithmFunctions(t)
 	default:
-		hash = tm.hashFnIdentity
-		equal = tm.equalFnIdentity
+		hash = tm.hashFnIdentityDescriptor
+		equal = tm.equalFnIdentityDescriptor
 	}
 
 	return
@@ -1704,13 +1768,13 @@
 }
 
 func (tm *TypeMap) makeCommonType(t types.Type) llvm.Value {
-	var vals [12]llvm.Value
+	var vals [11]llvm.Value
 	vals[0] = llvm.ConstInt(tm.ctx.Int8Type(), uint64(runtimeTypeKind(t)), false)
 	vals[1] = llvm.ConstInt(tm.ctx.Int8Type(), uint64(tm.Alignof(t)), false)
 	vals[2] = vals[1]
 	vals[3] = llvm.ConstInt(tm.inttype, uint64(tm.Sizeof(t)), false)
 	vals[4] = llvm.ConstInt(tm.ctx.Int32Type(), uint64(tm.getTypeHash(t)), false)
-	hash, equal := tm.getAlgorithmFunctions(t)
+	hash, equal := tm.getAlgorithmDescriptors(t)
 	vals[5] = hash
 	vals[6] = equal
 	vals[7] = tm.getGcPointer(t)
@@ -1718,13 +1782,12 @@
 	tm.writeType(t, &b)
 	vals[8] = tm.globalStringPtr(b.String())
 	vals[9] = tm.makeUncommonTypePtr(t)
-	if _, ok := t.(*types.Named); ok {
+	switch t.(type) {
+	case *types.Named, *types.Struct:
 		vals[10] = tm.getTypeDescriptorPointer(types.NewPointer(t))
-	} else {
+	default:
 		vals[10] = llvm.ConstPointerNull(llvm.PointerType(tm.commonTypeType, 0))
 	}
-	vals[11] = tm.zeroValue
-
 	return llvm.ConstNamedStruct(tm.commonTypeType, vals[:])
 }
 
Index: irgen/value.go
===================================================================
--- irgen/value.go
+++ irgen/value.go
@@ -17,6 +17,7 @@
 import (
 	"fmt"
 	"go/token"
+
 	"llvm.org/llgo/third_party/gotools/go/exact"
 	"llvm.org/llgo/third_party/gotools/go/types"
 	"llvm.org/llvm/bindings/go/llvm"
@@ -480,20 +481,8 @@
 
 		// string -> []byte
 		if isSlice(dsttyp, types.Byte) {
-			value := v.value
-			strdata := fr.builder.CreateExtractValue(value, 0, "")
-			strlen := fr.builder.CreateExtractValue(value, 1, "")
-
-			// Data must be copied, to prevent changes in
-			// the byte slice from mutating the string.
-			newdata := fr.createMalloc(strlen)
-			fr.memcpy(newdata, strdata, strlen)
-
-			struct_ := llvm.Undef(fr.types.ToLLVM(dsttyp))
-			struct_ = fr.builder.CreateInsertValue(struct_, newdata, 0, "")
-			struct_ = fr.builder.CreateInsertValue(struct_, strlen, 1, "")
-			struct_ = fr.builder.CreateInsertValue(struct_, strlen, 2, "")
-			return newValue(struct_, origdsttyp)
+			sliceValue := fr.runtime.stringToByteArray.callOnly(fr, v.value)[0]
+			return newValue(sliceValue, origdsttyp)
 		}
 
 		// string -> []rune
@@ -504,19 +493,10 @@
 
 	// []byte -> string
 	if isSlice(srctyp, types.Byte) && isString(dsttyp) {
-		value := v.value
-		data := fr.builder.CreateExtractValue(value, 0, "")
-		len := fr.builder.CreateExtractValue(value, 1, "")
-
-		// Data must be copied, to prevent changes in
-		// the byte slice from mutating the string.
-		newdata := fr.createMalloc(len)
-		fr.memcpy(newdata, data, len)
-
-		struct_ := llvm.Undef(fr.types.ToLLVM(types.Typ[types.String]))
-		struct_ = fr.builder.CreateInsertValue(struct_, newdata, 0, "")
-		struct_ = fr.builder.CreateInsertValue(struct_, len, 1, "")
-		return newValue(struct_, types.Typ[types.String])
+		data := fr.builder.CreateExtractValue(v.value, 0, "")
+		len := fr.builder.CreateExtractValue(v.value, 1, "")
+		stringValue := fr.runtime.byteArrayToString.callOnly(fr, data, len)[0]
+		return newValue(stringValue, dsttyp)
 	}
 
 	// []rune -> string
Index: libgo-check-failures.diff
===================================================================
--- libgo-check-failures.diff
+++ libgo-check-failures.diff
@@ -47,15 +47,3 @@
  		select {
  		case <-ch:
  		case <-time.After(time.Second * 4):
-diff -r a6e10414311a libgo/go/runtime/runtime_test.go
---- a/libgo/go/runtime/runtime_test.go	Fri Jan 16 07:57:02 2015 -0800
-+++ b/libgo/go/runtime/runtime_test.go	Fri Apr 03 15:07:47 2015 -0700
-@@ -176,6 +176,8 @@
- }
- 
- func TestSetPanicOnFault(t *testing.T) {
-+	t.Skip("skipping for llgo due to lack of non-call exception support")
-+
- 	// This currently results in a fault in the signal trampoline on
- 	// dragonfly/386 - see issue 7421.
- 	if GOOS == "dragonfly" && GOARCH == "386" {
Index: update_third_party.sh
===================================================================
--- update_third_party.sh
+++ update_third_party.sh
@@ -4,8 +4,8 @@
 llgosrcdir=$(dirname "$scriptpath")
 cd $llgosrcdir
 
-gofrontendrepo=https://code.google.com/p/gofrontend
-gofrontendrev=15a24202fa42
+gofrontendrepo=https://go.googlesource.com/gofrontend
+gofrontendrev=81eb6a3f425b2158c67ee32c0cc973a72ce9d6be
 
 gccrepo=svn://gcc.gnu.org/svn/gcc/trunk
 gccrev=219477
@@ -14,7 +14,7 @@
 gotoolsrev=d4e70101500b43ffe705d4c45e50dd4f1c8e3b2e
 
 linerrepo=https://github.com/peterh/liner.git
-linerrev=1bb0d1c1a25ed393d8feb09bab039b2b1b1fbced
+linerrev=4d47685ab2fd2dbb46c66b831344d558bc4be5b9
 
 tempdir=$(mktemp -d /tmp/update_third_party.XXXXXX)
 gofrontenddir=$tempdir/gofrontend
@@ -24,9 +24,21 @@
 rm -rf third_party
 mkdir -p third_party/gofrontend third_party/gotools
 
+git_clone() {
+    repo=$1
+    dir=$2
+    rev=$3
+    git clone $repo $dir
+    (
+        cd $dir
+        git checkout $rev
+        rm -fr .git
+    )
+}
+
 # --------------------- gofrontend ---------------------
 
-hg clone -r $gofrontendrev $gofrontendrepo $gofrontenddir
+git_clone $gofrontendrepo $gofrontenddir $gofrontendrev
 
 cp -r $gofrontenddir/LICENSE $gofrontenddir/libgo third_party/gofrontend
 
@@ -88,8 +100,7 @@
 
 # --------------------- go.tools ---------------------
 
-git clone $gotoolsrepo $gotoolsdir
-(cd $gotoolsdir && git checkout $gotoolsrev)
+git_clone $gotoolsrepo $gotoolsdir $gotoolsrev
 
 cp -r $gotoolsdir/LICENSE $gotoolsdir/go third_party/gotools
 
@@ -99,8 +110,7 @@
 
 # --------------------- peterh/liner -----------------
 
-git clone $linerrepo $linerdir
-(cd $linerdir && git checkout $linerrev && rm -rf .git)
+git_clone $linerrepo $linerdir $linerrev
 
 # --------------------- license check ---------------------