This patch updates libgo to the Go1.10beta1 release. The final Go 1.10 release is expected around February 1, so it's not clear how the release timing is going to work with GCC 8. In any case this updates GCC to something pretty close to the final Go 1.10 release.
A few changes to the frontend were required to match changes in the runtime map code, and to handle some no-writebarrier cases in the runtime package. As usual with these updates the complete patch is too large to include in this e-mail message. I've just included the changes to gccgo-specific code. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian 2018-01-08 Ian Lance Taylor <i...@golang.org> * Makefile.am (go_cmd_vet_files): New variable. (go_cmd_buildid_files, go_cmd_test2json_files): New variables. (s-zdefaultcc): Change from constants to functions. (noinst_PROGRAMS): Add vet, buildid, and test2json. (cgo$(EXEEXT)): Link against $(LIBGOTOOL). (vet$(EXEEXT)): New target. (buildid$(EXEEXT)): New target. (test2json$(EXEEXT)): New target. (install-exec-local): Install all $(noinst_PROGRAMS). (uninstall-local): Uninstasll all $(noinst_PROGRAMS). (check-go-tool): Depend on $(noinst_PROGRAMS). Copy down objabi.go. (check-runtime): Depend on $(noinst_PROGRAMS). (check-cgo-test, check-carchive-test): Likewise. (check-vet): New target. (check): Depend on check-vet. Look at cmd_vet-testlog. (.PHONY): Add check-vet. * Makefile.in: Rebuild.
Index: gcc/go/gofrontend/MERGE =================================================================== --- gcc/go/gofrontend/MERGE (revision 256306) +++ gcc/go/gofrontend/MERGE (working copy) @@ -1,4 +1,4 @@ -1319f36ccc65cf802b8e17ddd3d2da3ca6d82f4c +dbc0c7e4329aada2ae3554c20cfb8cfa48041213 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. Index: gcc/go/gofrontend/expressions.cc =================================================================== --- gcc/go/gofrontend/expressions.cc (revision 256262) +++ gcc/go/gofrontend/expressions.cc (working copy) @@ -7483,6 +7483,7 @@ Builtin_call_expression::lower_make(Stat return Expression::make_error(this->location()); } len_arg = Expression::make_integer_ul(0, NULL, loc); + len_small = true; } else { @@ -7551,9 +7552,23 @@ Builtin_call_expression::lower_make(Stat else if (is_map) { Expression* type_arg = Expression::make_type_descriptor(type, type_loc); - call = Runtime::make_call(Runtime::MAKEMAP, loc, 4, type_arg, len_arg, - Expression::make_nil(loc), - Expression::make_nil(loc)); + if (!len_small) + call = Runtime::make_call(Runtime::MAKEMAP64, loc, 3, type_arg, + len_arg, + Expression::make_nil(loc)); + else + { + Numeric_constant nclen; + unsigned long vlen; + if (len_arg->numeric_constant_value(&nclen) + && nclen.to_unsigned_long(&vlen) == Numeric_constant::NC_UL_VALID + && vlen <= Map_type::bucket_size) + call = Runtime::make_call(Runtime::MAKEMAP_SMALL, loc, 0); + else + call = Runtime::make_call(Runtime::MAKEMAP, loc, 3, type_arg, + len_arg, + Expression::make_nil(loc)); + } } else if (is_chan) { @@ -9503,14 +9518,8 @@ Call_expression::do_lower(Gogo* gogo, Na // could implement them in normal code, but then we would have to // explicitly unwind the stack. These functions are intended to be // efficient. Note that this technique obviously only works for - // direct calls, but that is the only way they are used. The actual - // argument to these functions is always the address of a parameter; - // we don't need that for the GCC builtin functions, so we just - // ignore it. - if (gogo->compiling_runtime() - && this->args_ != NULL - && this->args_->size() == 1 - && gogo->package_name() == "runtime") + // direct calls, but that is the only way they are used. + if (gogo->compiling_runtime() && gogo->package_name() == "runtime") { Func_expression* fe = this->fn_->func_expression(); if (fe != NULL @@ -9518,15 +9527,21 @@ Call_expression::do_lower(Gogo* gogo, Na && fe->named_object()->package() == NULL) { std::string n = Gogo::unpack_hidden_name(fe->named_object()->name()); - if (n == "getcallerpc") + if ((this->args_ == NULL || this->args_->size() == 0) + && n == "getcallerpc") { static Named_object* builtin_return_address; return this->lower_to_builtin(&builtin_return_address, "__builtin_return_address", 0); } - else if (n == "getcallersp") + else if (this->args_ != NULL + && this->args_->size() == 1 + && n == "getcallersp") { + // The actual argument to getcallersp is always the + // address of a parameter; we don't need that for the + // GCC builtin function, so we just ignore it. static Named_object* builtin_frame_address; return this->lower_to_builtin(&builtin_frame_address, "__builtin_frame_address", @@ -10027,7 +10042,7 @@ Call_expression::do_check_types(Gogo*) } const Typed_identifier_list* parameters = fntype->parameters(); - if (this->args_ == NULL) + if (this->args_ == NULL || this->args_->size() == 0) { if (parameters != NULL && !parameters->empty()) this->report_error(_("not enough arguments")); Index: gcc/go/gofrontend/runtime.def =================================================================== --- gcc/go/gofrontend/runtime.def (revision 256262) +++ gcc/go/gofrontend/runtime.def (working copy) @@ -91,9 +91,14 @@ DEF_GO_RUNTIME(MAKESLICE64, "runtime.mak R1(SLICE)) -// Make a map. -DEF_GO_RUNTIME(MAKEMAP, "runtime.makemap", P4(TYPE, INT64, POINTER, POINTER), - R1(MAP)) +// Make a map with a hint and an (optional, unused) map structure. +DEF_GO_RUNTIME(MAKEMAP, "runtime.makemap", P3(TYPE, INT, POINTER), + R1(MAP)) +DEF_GO_RUNTIME(MAKEMAP64, "runtime.makemap64", P3(TYPE, INT64, POINTER), + R1(MAP)) + +// Make a map with no hint, or a small constant hint. +DEF_GO_RUNTIME(MAKEMAP_SMALL, "runtime.makemap_small", P0(), R1(MAP)) // Build a map from a composite literal. DEF_GO_RUNTIME(CONSTRUCT_MAP, "__go_construct_map", Index: gcc/go/gofrontend/types.cc =================================================================== --- gcc/go/gofrontend/types.cc (revision 256262) +++ gcc/go/gofrontend/types.cc (working copy) @@ -7830,7 +7830,7 @@ Map_type::do_get_backend(Gogo* gogo) bfields[7].btype = uintptr_type->get_backend(gogo); bfields[7].location = bloc; - bfields[8].name = "overflow"; + bfields[8].name = "extra"; bfields[8].btype = bpvt; bfields[8].location = bloc; @@ -8144,21 +8144,23 @@ Map_type::hmap_type(Type* bucket_type) Type* int_type = Type::lookup_integer_type("int"); Type* uint8_type = Type::lookup_integer_type("uint8"); + Type* uint16_type = Type::lookup_integer_type("uint16"); Type* uint32_type = Type::lookup_integer_type("uint32"); Type* uintptr_type = Type::lookup_integer_type("uintptr"); Type* void_ptr_type = Type::make_pointer_type(Type::make_void_type()); Type* ptr_bucket_type = Type::make_pointer_type(bucket_type); - Struct_type* ret = make_builtin_struct_type(8, + Struct_type* ret = make_builtin_struct_type(9, "count", int_type, "flags", uint8_type, "B", uint8_type, + "noverflow", uint16_type, "hash0", uint32_type, "buckets", ptr_bucket_type, "oldbuckets", ptr_bucket_type, "nevacuate", uintptr_type, - "overflow", void_ptr_type); + "extra", void_ptr_type); ret->set_is_struct_incomparable(); this->hmap_type_ = ret; return ret; @@ -8191,18 +8193,22 @@ Map_type::hiter_type(Gogo* gogo) Type* hmap_type = this->hmap_type(bucket_type); Type* hmap_ptr_type = Type::make_pointer_type(hmap_type); Type* void_ptr_type = Type::make_pointer_type(Type::make_void_type()); + Type* bool_type = Type::lookup_bool_type(); - Struct_type* ret = make_builtin_struct_type(12, + Struct_type* ret = make_builtin_struct_type(15, "key", key_ptr_type, "val", val_ptr_type, "t", uint8_ptr_type, "h", hmap_ptr_type, "buckets", bucket_ptr_type, "bptr", bucket_ptr_type, - "overflow0", void_ptr_type, - "overflow1", void_ptr_type, + "overflow", void_ptr_type, + "oldoverflow", void_ptr_type, "startBucket", uintptr_type, - "stuff", uintptr_type, + "offset", uint8_type, + "wrapped", bool_type, + "B", uint8_type, + "i", uint8_type, "bucket", uintptr_type, "checkBucket", uintptr_type); ret->set_is_struct_incomparable(); Index: gcc/go/gofrontend/types.h =================================================================== --- gcc/go/gofrontend/types.h (revision 256262) +++ gcc/go/gofrontend/types.h (working copy) @@ -2826,6 +2826,9 @@ class Map_type : public Type static Type* make_map_type_descriptor_type(); + // This must be in sync with libgo/go/runtime/hashmap.go. + static const int bucket_size = 8; + protected: int do_traverse(Traverse*); @@ -2867,7 +2870,6 @@ class Map_type : public Type private: // These must be in sync with libgo/go/runtime/hashmap.go. - static const int bucket_size = 8; static const int max_key_size = 128; static const int max_val_size = 128; static const int max_zero_size = 1024; Index: gcc/go/gofrontend/wb.cc =================================================================== --- gcc/go/gofrontend/wb.cc (revision 256262) +++ gcc/go/gofrontend/wb.cc (working copy) @@ -331,6 +331,25 @@ Gogo::assign_needs_write_barrier(Express if (!lhs->type()->has_pointer()) return false; + // An assignment to a field is handled like an assignment to the + // struct. + while (true) + { + // Nothing to do for a type that can not be in the heap, or a + // pointer to a type that can not be in the heap. We check this + // at each level of a struct. + if (!lhs->type()->in_heap()) + return false; + if (lhs->type()->points_to() != NULL + && !lhs->type()->points_to()->in_heap()) + return false; + + Field_reference_expression* fre = lhs->field_reference_expression(); + if (fre == NULL) + break; + lhs = fre->expr(); + } + // Nothing to do for an assignment to a temporary. if (lhs->temporary_reference_expression() != NULL) return false; @@ -359,12 +378,30 @@ Gogo::assign_needs_write_barrier(Express } } - // Nothing to do for a type that can not be in the heap, or a - // pointer to a type that can not be in the heap. - if (!lhs->type()->in_heap()) - return false; - if (lhs->type()->points_to() != NULL && !lhs->type()->points_to()->in_heap()) - return false; + // For a struct assignment, we don't need a write barrier if all the + // pointer types can not be in the heap. + Struct_type* st = lhs->type()->struct_type(); + if (st != NULL) + { + bool in_heap = false; + const Struct_field_list* fields = st->fields(); + for (Struct_field_list::const_iterator p = fields->begin(); + p != fields->end(); + p++) + { + Type* ft = p->type(); + if (!ft->has_pointer()) + continue; + if (!ft->in_heap()) + continue; + if (ft->points_to() != NULL && !ft->points_to()->in_heap()) + continue; + in_heap = true; + break; + } + if (!in_heap) + return false; + } // Write barrier needed in other cases. return true; Index: libgo/MERGE =================================================================== --- libgo/MERGE (revision 256262) +++ libgo/MERGE (working copy) @@ -1,4 +1,4 @@ -c8aec4095e089ff6ac50d18e97c3f46561f14f48 +9ce6b5c2ed5d3d5251b9a6a0c548d5fb2c8567e8 The first line of this file holds the git revision number of the last merge done from the master library sources. Index: libgo/Makefile.am =================================================================== --- libgo/Makefile.am (revision 256262) +++ libgo/Makefile.am (working copy) @@ -400,8 +400,11 @@ toolexeclibgounicode_DATA = \ # internal packages nothing will explicitly depend on them. # Force them to be built. noinst_DATA = \ + golang_org/x/net/internal/nettest.gox \ + golang_org/x/net/nettest.gox \ internal/testenv.gox \ - net/internal/socktest.gox + net/internal/socktest.gox \ + os/signal/internal/pty.gox if LIBGO_IS_RTEMS rtems_task_variable_add_file = runtime/rtems-task-variable-add.c @@ -533,6 +536,24 @@ s-version: Makefile $(SHELL) $(srcdir)/mvifdiff.sh version.go.tmp version.go $(STAMP) $@ +objabi.go: s-objabi; @true +s-objabi: Makefile + rm -f objabi.go.tmp + echo "package objabi" > objabi.go.tmp + echo "import \"runtime\"" >> objabi.go.tmp + echo 'const defaultGOROOT = `$(prefix)`' >> objabi.go.tmp + echo 'const defaultGO386 = `sse2`' >> objabi.go.tmp + echo 'const defaultGOARM = `5`' >> objabi.go.tmp + echo 'const defaultGOMIPS = `hardfloat`' >> objabi.go.tmp + echo 'const defaultGOOS = runtime.GOOS' >> objabi.go.tmp + echo 'const defaultGOARCH = runtime.GOARCH' >> objabi.go.tmp + echo 'const defaultGO_EXTLINK_ENABLED = ``' >> objabi.go.tmp + echo 'const version = `'`cat $(srcdir)/VERSION | sed 1q`' '`$(GOC) --version | sed 1q`'`' >> objabi.go.tmp + echo 'const stackGuardMultiplier = 1' >> objabi.go.tmp + echo 'const goexperiment = ``' >> objabi.go.tmp + $(SHELL) $(srcdir)/mvifdiff.sh objabi.go.tmp objabi.go + $(STAMP) $@ + runtime_sysinfo.go: s-runtime_sysinfo; @true s-runtime_sysinfo: $(srcdir)/mkrsysinfo.sh gen-sysinfo.go GOARCH=$(GOARCH) GOOS=$(GOOS) $(SHELL) $(srcdir)/mkrsysinfo.sh @@ -553,10 +574,11 @@ zdefaultcc.go: s-zdefaultcc; @true s-zdefaultcc: Makefile echo 'package cfg' > zdefaultcc.go.tmp echo >> zdefaultcc.go.tmp - echo 'const DefaultGCCGO = "$(bindir)/$(GCCGO_INSTALL_NAME)"' >> zdefaultcc.go.tmp - echo 'const DefaultCC = "$(GCC_INSTALL_NAME)"' >> zdefaultcc.go.tmp - echo 'const DefaultCXX = "$(GXX_INSTALL_NAME)"' >> zdefaultcc.go.tmp + echo 'func DefaultGCCGO(goos, goarch string) string { return "$(bindir)/$(GCCGO_INSTALL_NAME)" }' >> zdefaultcc.go.tmp + echo 'func DefaultCC(goos, goarch string) string { return "$(GCC_INSTALL_NAME)" }' >> zdefaultcc.go.tmp + echo 'func DefaultCXX(goos, goarch string) string { return "$(GXX_INSTALL_NAME)" }' >> zdefaultcc.go.tmp echo 'const DefaultPkgConfig = "pkg-config"' >> zdefaultcc.go.tmp + echo 'var OSArchSupportsCgo = map[string]bool{}' >> zdefaultcc.go.tmp $(SHELL) $(srcdir)/../move-if-change zdefaultcc.go.tmp zdefaultcc.go $(STAMP) $@ @@ -758,11 +780,15 @@ PACKAGES = \ go/types \ golang_org/x/crypto/chacha20poly1305 \ golang_org/x/crypto/chacha20poly1305/internal/chacha20 \ + golang_org/x/crypto/cryptobyte \ + golang_org/x/crypto/cryptobyte/asn1 \ golang_org/x/crypto/curve25519 \ golang_org/x/crypto/poly1305 \ golang_org/x/net/http2/hpack \ golang_org/x/net/idna \ + golang_org/x/net/internal/nettest \ golang_org/x/net/lex/httplex \ + golang_org/x/net/nettest \ golang_org/x/net/proxy \ golang_org/x/text/secure/bidirule \ golang_org/x/text/transform \ @@ -824,6 +850,7 @@ PACKAGES = \ os \ os/exec \ os/signal \ + os/signal/internal/pty \ os/user \ path \ path/filepath \ @@ -905,7 +932,7 @@ libgolibbegin_a_CFLAGS = $(AM_CFLAGS) -f GOTOOL_PACKAGES = \ cmd/go/internal/base \ cmd/go/internal/bug \ - cmd/go/internal/buildid \ + cmd/go/internal/cache \ cmd/go/internal/cfg \ cmd/go/internal/clean \ cmd/go/internal/cmdflag \ @@ -927,7 +954,12 @@ GOTOOL_PACKAGES = \ cmd/go/internal/web \ cmd/go/internal/work \ cmd/internal/browser \ - cmd/internal/objabi + cmd/internal/buildid \ + cmd/internal/edit \ + cmd/internal/objabi \ + cmd/internal/test2json \ + cmd/vet/internal/cfg \ + cmd/vet/internal/whitelist libgotool_a_SOURCES = libgotool_a_DEPENDENCIES = $(addsuffix .lo,$(GOTOOL_PACKAGES)) @@ -1136,17 +1168,23 @@ runtime_pprof_check_GOCFLAGS = -static-l extra_go_files_runtime_internal_sys = version.go runtime/internal/sys.lo.dep: $(extra_go_files_runtime_internal_sys) +extra_go_files_cmd_internal_objabi = objabi.go +cmd/internal/objabi.lo.dep: $(extra_go_files_cmd_internal_objabi) + extra_go_files_cmd_go_internal_cfg = zdefaultcc.go cmd/go/internal/cfg.lo.dep: $(extra_go_files_cmd_go_internal_cfg) extra_go_files_cmd_go_internal_load = zstdpkglist.go cmd/go/internal/load.lo.dep: $(extra_go_files_cmd_go_internal_load) +extra_check_libs_cmd_go_internal_cache = $(abs_builddir)/libgotool.a extra_check_libs_cmd_go_internal_generate = $(abs_builddir)/libgotool.a extra_check_libs_cmd_go_internal_get = $(abs_builddir)/libgotool.a extra_check_libs_cmd_go_internal_load = $(abs_builddir)/libgotool.a extra_check_libs_cmd_go_internal_work = $(abs_builddir)/libgotool.a +extra_check_libs_cmd_vet_internal_cfg = $(abs_builddir)/libgotool.a + # FIXME: The following C files may as well move to the runtime # directory and be treated like other C files. @@ -1233,10 +1271,12 @@ TEST_PACKAGES = \ bufio/check \ bytes/check \ context/check \ + crypto/check \ errors/check \ expvar/check \ flag/check \ fmt/check \ + hash/check \ html/check \ image/check \ io/check \ @@ -1258,11 +1298,16 @@ TEST_PACKAGES = \ unicode/check \ archive/tar/check \ archive/zip/check \ + cmd/go/internal/cache/check \ cmd/go/internal/generate/check \ cmd/go/internal/get/check \ cmd/go/internal/load/check \ cmd/go/internal/work/check \ + cmd/internal/buildid/check \ + cmd/internal/edit/check \ cmd/internal/objabi/check \ + cmd/internal/test2json/check \ + cmd/vet/internal/cfg/check \ compress/bzip2/check \ compress/flate/check \ compress/gzip/check \ @@ -1315,6 +1360,7 @@ TEST_PACKAGES = \ go/constant/check \ go/doc/check \ go/format/check \ + go/importer/check \ go/internal/gcimporter/check \ go/internal/gccgoimporter/check \ go/internal/srcimporter/check \ @@ -1325,6 +1371,7 @@ TEST_PACKAGES = \ go/types/check \ golang_org/x/crypto/chacha20poly1305/check \ golang_org/x/crypto/chacha20poly1305/internal/chacha20/check \ + golang_org/x/crypto/cryptobyte/check \ golang_org/x/crypto/curve25519/check \ golang_org/x/crypto/poly1305/check \ golang_org/x/net/http2/hpack/check \ Index: libgo/VERSION =================================================================== --- libgo/VERSION (revision 256262) +++ libgo/VERSION (working copy) @@ -1 +1 @@ -go1.9 +go1.10beta1 Index: libgo/configure.ac =================================================================== --- libgo/configure.ac (revision 256306) +++ libgo/configure.ac (working copy) @@ -11,7 +11,7 @@ AC_INIT(package-unused, version-unused,, AC_CONFIG_SRCDIR(Makefile.am) AC_CONFIG_HEADER(config.h) -libtool_VERSION=12:0:0 +libtool_VERSION=13:0:0 AC_SUBST(libtool_VERSION) AM_ENABLE_MULTILIB(, ..) @@ -215,7 +215,7 @@ ALLGOARCHFAMILY="I386 ALPHA AMD64 ARM AR GOARCH=unknown GOARCH_FAMILY=unknown -GOARCH_BIGENDIAN=0 +GOARCH_BIGENDIAN=false GOARCH_CACHELINESIZE=64 GOARCH_PHYSPAGESIZE=4096 GOARCH_PCQUANTUM=1 @@ -243,6 +243,12 @@ case ${host} in GOARCH_CACHELINESIZE=32 GOARCH_PCQUANTUM=4 GOARCH_MINFRAMESIZE=4 + case ${host} in + arm*b*-*-*) + GOARCH=armbe + GOARCH_BIGENDIAN=true + ;; + esac ;; changequote(,)dnl i[34567]86-*-* | x86_64-*-*) @@ -270,7 +276,7 @@ GOARCH_HUGEPAGESIZE="1 << 21" m68k*-*-*) GOARCH=m68k GOARCH_FAMILY=M68K - GOARCH_BIGENDIAN=1 + GOARCH_BIGENDIAN=true GOARCH_CACHELINESIZE=16 GOARCH_PCQUANTUM=4 GOARCH_INT64ALIGN=2 @@ -313,7 +319,7 @@ GOARCH_HUGEPAGESIZE="1 << 21" GOARCH="${GOARCH}le" ;; *) - GOARCH_BIGENDIAN=1 + GOARCH_BIGENDIAN=true ;; esac GOARCH_CACHELINESIZE=32 @@ -327,7 +333,7 @@ GOARCH_HUGEPAGESIZE="1 << 21" #endif], [GOARCH=ppc GOARCH_FAMILY=PPC -GOARCH_BIGENDIAN=1 +GOARCH_BIGENDIAN=true ], [ GOARCH_FAMILY=PPC64 @@ -338,7 +344,7 @@ AC_COMPILE_IFELSE([ [GOARCH=ppc64le ], [GOARCH=ppc64 -GOARCH_BIGENDIAN=1 +GOARCH_BIGENDIAN=true ])]) GOARCH_PHYSPAGESIZE=65536 GOARCH_PCQUANTUM=4 @@ -356,7 +362,7 @@ GOARCH_MINFRAMESIZE=4 GOARCH_FAMILY=S390X GOARCH_MINFRAMESIZE=8 ]) - GOARCH_BIGENDIAN=1 + GOARCH_BIGENDIAN=true GOARCH_CACHELINESIZE=256 GOARCH_PCQUANTUM=2 ;; @@ -371,7 +377,7 @@ GOARCH_FAMILY=SPARC [GOARCH=sparc64 GOARCH_FAMILY=SPARC64 ]) - GOARCH_BIGENDIAN=1 + GOARCH_BIGENDIAN=true GOARCH_PHYSPAGESIZE=8192 GOARCH_PCQUANTUM=4 ;; @@ -718,7 +724,7 @@ AC_COMPILE_IFELSE([int i;], CFLAGS=$CFLAGS_hold]) MATH_FLAG= if test "$libgo_cv_c_fancymath" = yes; then - MATH_FLAG="-mfancy-math-387 -funsafe-math-optimizations" + MATH_FLAG="-mfancy-math-387 -funsafe-math-optimizations -fno-math-errno" else MATH_FLAG="-ffp-contract=off" fi Index: libgo/runtime/go-callers.c =================================================================== --- libgo/runtime/go-callers.c (revision 256262) +++ libgo/runtime/go-callers.c (working copy) @@ -127,8 +127,12 @@ callback (void *data, uintptr_t pc, cons p = filename; if (__builtin_strcmp (p, "/proc.c") == 0) { - if (__builtin_strcmp (function, "kickoff") == 0 - || __builtin_strcmp (function, "runtime.mstart") == 0 + if (__builtin_strcmp (function, "runtime_mstart") == 0) + return 1; + } + else if (__builtin_strcmp (p, "/proc.go") == 0) + { + if (__builtin_strcmp (function, "runtime.kickoff") == 0 || __builtin_strcmp (function, "runtime.main") == 0) return 1; } @@ -184,6 +188,21 @@ runtime_callers (int32 skip, Location *l backtrace_full (__go_get_backtrace_state (), 0, callback, error_callback, &data); runtime_xadd (&runtime_in_callers, -1); + + /* For some reason GCC sometimes loses the name of a thunk function + at the top of the stack. If we are skipping thunks, skip that + one too. */ + if (!keep_thunks + && data.index > 2 + && locbuf[data.index - 2].function.len == 0 + && locbuf[data.index - 1].function.str != NULL + && __builtin_strcmp ((const char *) locbuf[data.index - 1].function.str, + "runtime.kickoff") == 0) + { + locbuf[data.index - 2] = locbuf[data.index - 1]; + --data.index; + } + return data.index; } Index: libgo/runtime/proc.c =================================================================== --- libgo/runtime/proc.c (revision 256262) +++ libgo/runtime/proc.c (working copy) @@ -32,6 +32,8 @@ extern void *__splitstack_makecontext(si extern void * __splitstack_resetcontext(void *context[10], size_t *); +extern void __splitstack_releasecontext(void *context[10]); + extern void *__splitstack_find(void *, void *, size_t *, void **, void **, void **); @@ -269,6 +271,9 @@ runtime_newosproc(M *mp) runtime_printf("pthread_create failed: %d\n", ret); runtime_throw("pthread_create"); } + + if(pthread_attr_destroy(&attr) != 0) + runtime_throw("pthread_attr_destroy"); } // Switch context to a different goroutine. This is like longjmp. @@ -377,10 +382,12 @@ extern void kickoff(void) __asm__(GOSYM_PREFIX "runtime.kickoff"); extern void minit(void) __asm__(GOSYM_PREFIX "runtime.minit"); -extern void mstart1(void) +extern void mstart1(int32) __asm__(GOSYM_PREFIX "runtime.mstart1"); extern void stopm(void) __asm__(GOSYM_PREFIX "runtime.stopm"); +extern void mexit(bool) + __asm__(GOSYM_PREFIX "runtime.mexit"); extern void handoffp(P*) __asm__(GOSYM_PREFIX "runtime.handoffp"); extern void wakep(void) @@ -519,6 +526,11 @@ runtime_mstart(void *arg) *(int*)0x21 = 0x21; } + if(mp->exiting) { + mexit(true); + return nil; + } + // Initial call to getcontext--starting thread. #ifdef USING_SPLIT_STACK @@ -528,7 +540,7 @@ runtime_mstart(void *arg) } #endif - mstart1(); + mstart1(0); // mstart1 does not return, but we need a return statement // here to avoid a compiler warning. @@ -751,6 +763,30 @@ runtime_malg(bool allocatestack, bool si return newg; } +void stackfree(G*) + __asm__(GOSYM_PREFIX "runtime.stackfree"); + +// stackfree frees the stack of a g. +void +stackfree(G* gp) +{ +#if USING_SPLIT_STACK + __splitstack_releasecontext((void*)(&gp->stackcontext[0])); +#else + // If gcstacksize is 0, the stack is allocated by libc and will be + // released when the thread exits. Otherwise, in 64-bit mode it was + // allocated using sysAlloc and in 32-bit mode it was allocated + // using garbage collected memory. + if (gp->gcstacksize != 0) { + if (sizeof(void*) == 8) { + runtime_sysFree(gp->gcinitialsp, gp->gcstacksize, &getMemstats()->stacks_sys); + } + gp->gcinitialsp = nil; + gp->gcstacksize = 0; + } +#endif +} + void resetNewG(G*, void **, uintptr*) __asm__(GOSYM_PREFIX "runtime.resetNewG"); Index: libgo/runtime/runtime.h =================================================================== --- libgo/runtime/runtime.h (revision 256262) +++ libgo/runtime/runtime.h (working copy) @@ -265,11 +265,12 @@ void* runtime_mallocgc(uintptr, const Ty __asm__ (GOSYM_PREFIX "runtime.mallocgc"); void* runtime_sysAlloc(uintptr, uint64*) __asm__ (GOSYM_PREFIX "runtime.sysAlloc"); +void runtime_sysFree(void*, uintptr, uint64*) + __asm__ (GOSYM_PREFIX "runtime.sysFree"); void runtime_mprofinit(void); #define runtime_getcallersp(p) __builtin_frame_address(0) void runtime_mcall(FuncVal*) __asm__ (GOSYM_PREFIX "runtime.mcall"); -uint32 runtime_fastrand(void) __asm__ (GOSYM_PREFIX "runtime.fastrand"); int32 runtime_timediv(int64, int32, int32*) __asm__ (GOSYM_PREFIX "runtime.timediv"); int32 runtime_round2(int32 x); // round x up to a power of 2. Index: libgo/runtime/runtime_c.c =================================================================== --- libgo/runtime/runtime_c.c (revision 256262) +++ libgo/runtime/runtime_c.c (working copy) @@ -33,21 +33,6 @@ runtime_atoi(const byte *p, intgo len) return n; } -uint32 -runtime_fastrand(void) -{ - M *m; - uint32 x; - - m = runtime_m(); - x = m->fastrand; - x += x; - if(x & 0x80000000L) - x ^= 0x88888eefUL; - m->fastrand = x; - return x; -} - int64 runtime_cputicks(void) { Index: libgo/testsuite/gotest =================================================================== --- libgo/testsuite/gotest (revision 256262) +++ libgo/testsuite/gotest (working copy) @@ -510,7 +510,7 @@ localname() { ppc64*) text="[TD]" ;; esac - symtogo='sed -e s/_test/XXXtest/ -e s/.*_\([^_]*\.\)/\1/ -e s/XXXtest/_test/' + symtogo='sed -e s/_test\([^A-Za-z0-9]\)/XXXtest\1/ -e s/.*_\([^_]*\.\)/\1/ -e s/XXXtest/_test/' # test functions are named TestFoo # the grep -v eliminates methods and other special names Index: libgo/go/runtime/cgo_gccgo.go =================================================================== --- libgo/go/runtime/cgo_gccgo.go (revision 256262) +++ libgo/go/runtime/cgo_gccgo.go (working copy) @@ -27,6 +27,13 @@ var iscgo bool // The extra M must be created before any C/C++ code calls cgocallback. var cgoHasExtraM bool +// cgoAlwaysFalse is a boolean value that is always false. +// The cgo-generated code says if cgoAlwaysFalse { cgoUse(p) }. +// The compiler cannot see that cgoAlwaysFalse is always false, +// so it emits the test and keeps the call, giving the desired +// escape analysis result. The test is cheaper than the call. +var cgoAlwaysFalse bool + // Cgocall prepares to call from code written in Go to code written in // C/C++. This takes the current goroutine out of the Go scheduler, as // though it were making a system call. Otherwise the program can @@ -37,12 +44,11 @@ var cgoHasExtraM bool // defer syscall.Cgocalldone() // cfunction() func Cgocall() { - lockOSThread() mp := getg().m mp.ncgocall++ mp.ncgo++ - mp.incgo = true entersyscall(0) + mp.incgo = true } // CgocallDone prepares to return to Go code from C/C++ code. @@ -59,8 +65,6 @@ func CgocallDone() { if readgstatus(gp)&^_Gscan == _Gsyscall { exitsyscall(0) } - - unlockOSThread() } // CgocallBack is used when calling from C/C++ code into Go code. @@ -78,6 +82,8 @@ func CgocallBack() { mp.dropextram = true } + lockOSThread() + exitsyscall(0) gp.m.incgo = false @@ -100,6 +106,8 @@ func CgocallBack() { // CgocallBackDone prepares to return to C/C++ code that has called // into Go code. func CgocallBackDone() { + unlockOSThread() + // If we are the top level Go function called from C/C++, then // we need to release the m. But don't release it if we are // panicing; since this is the top level, we are going to Index: libgo/go/runtime/mem_gccgo.go =================================================================== --- libgo/go/runtime/mem_gccgo.go (revision 256262) +++ libgo/go/runtime/mem_gccgo.go (working copy) @@ -13,9 +13,10 @@ import ( // Functions called by C code. //go:linkname sysAlloc runtime.sysAlloc +//go:linkname sysFree runtime.sysFree //extern mmap -func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uintptr) unsafe.Pointer +func sysMmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uintptr) unsafe.Pointer //extern munmap func munmap(addr unsafe.Pointer, length uintptr) int32 @@ -40,6 +41,14 @@ func init() { } } +func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uintptr) (unsafe.Pointer, int) { + p := sysMmap(addr, n, prot, flags, fd, off) + if uintptr(p) == _MAP_FAILED { + return nil, errno() + } + return p, 0 +} + // NOTE: vec must be just 1 byte long here. // Mincore returns ENOMEM if any of the pages are unmapped, // but we want to know that all of the pages are unmapped. @@ -75,31 +84,30 @@ func addrspace_free(v unsafe.Pointer, n return true } -func mmap_fixed(v unsafe.Pointer, n uintptr, prot, flags, fd int32, offset uintptr) unsafe.Pointer { - p := mmap(v, n, prot, flags, fd, offset) +func mmap_fixed(v unsafe.Pointer, n uintptr, prot, flags, fd int32, offset uintptr) (unsafe.Pointer, int) { + p, err := mmap(v, n, prot, flags, fd, offset) // On some systems, mmap ignores v without // MAP_FIXED, so retry if the address space is free. if p != v && addrspace_free(v, n) { - if uintptr(p) != _MAP_FAILED { + if err == 0 { munmap(p, n) } - p = mmap(v, n, prot, flags|_MAP_FIXED, fd, offset) + p, err = mmap(v, n, prot, flags|_MAP_FIXED, fd, offset) } - return p + return p, err } // Don't split the stack as this method may be invoked without a valid G, which // prevents us from allocating more stack. //go:nosplit func sysAlloc(n uintptr, sysStat *uint64) unsafe.Pointer { - p := mmap(nil, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, mmapFD, 0) - if uintptr(p) == _MAP_FAILED { - errval := errno() - if errval == _EACCES { + p, err := mmap(nil, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, mmapFD, 0) + if err != 0 { + if err == _EACCES { print("runtime: mmap: access denied\n") exit(2) } - if errval == _EAGAIN { + if err == _EAGAIN { print("runtime: mmap: too much locked memory (check 'ulimit -l').\n") exit(2) } @@ -225,9 +233,9 @@ func sysReserve(v unsafe.Pointer, n uint // if we can reserve at least 64K and check the assumption in SysMap. // Only user-mode Linux (UML) rejects these requests. if sys.PtrSize == 8 && uint64(n) > 1<<32 { - p := mmap_fixed(v, 64<<10, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE, mmapFD, 0) - if p != v { - if uintptr(p) != _MAP_FAILED { + p, err := mmap_fixed(v, 64<<10, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE, mmapFD, 0) + if p != v || err != 0 { + if err == 0 { munmap(p, 64<<10) } return nil @@ -237,8 +245,8 @@ func sysReserve(v unsafe.Pointer, n uint return v } - p := mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE, mmapFD, 0) - if uintptr(p) == _MAP_FAILED { + p, err := mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE, mmapFD, 0) + if err != 0 { return nil } *reserved = true @@ -259,12 +267,12 @@ func sysMap(v unsafe.Pointer, n uintptr, // to do this - we do not on other platforms. flags |= _MAP_FIXED } - p := mmap_fixed(v, n, _PROT_READ|_PROT_WRITE, flags, mmapFD, 0) - if uintptr(p) == _MAP_FAILED && errno() == _ENOMEM { + p, err := mmap_fixed(v, n, _PROT_READ|_PROT_WRITE, flags, mmapFD, 0) + if err == _ENOMEM { throw("runtime: out of memory") } - if p != v { - print("runtime: address space conflict: map(", v, ") = ", p, "\n") + if p != v || err != 0 { + print("runtime: address space conflict: map(", v, ") = ", p, " (err ", err, ")\n") throw("runtime: address space conflict") } return @@ -275,11 +283,11 @@ func sysMap(v unsafe.Pointer, n uintptr, // So always unmap first even if it is already unmapped. munmap(v, n) } - p := mmap(v, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_FIXED|_MAP_PRIVATE, mmapFD, 0) - if uintptr(p) == _MAP_FAILED && errno() == _ENOMEM { + p, err := mmap(v, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_FIXED|_MAP_PRIVATE, mmapFD, 0) + if err == _ENOMEM { throw("runtime: out of memory") } - if p != v { + if p != v || err != 0 { throw("runtime: cannot map pages in arena address space") } } Index: libgo/go/runtime/mgc_gccgo.go =================================================================== --- libgo/go/runtime/mgc_gccgo.go (revision 256262) +++ libgo/go/runtime/mgc_gccgo.go (working copy) @@ -6,7 +6,10 @@ package runtime -import "unsafe" +import ( + "runtime/internal/sys" + "unsafe" +) // gcRoot is a single GC root: a variable plus a ptrmask. type gcRoot struct { @@ -85,3 +88,21 @@ func checkPreempt() { gp.scanningself = false mcall(gopreempt_m) } + +// gcWriteBarrier implements a write barrier. This is implemented in +// assembly in the gc library, but there is no special advantage to +// doing so with gccgo. +//go:nosplit +//go:nowritebarrier +func gcWriteBarrier(dst *uintptr, src uintptr) { + buf := &getg().m.p.ptr().wbBuf + next := buf.next + np := next + 2*sys.PtrSize + buf.next = np + *(*uintptr)(unsafe.Pointer(next)) = src + *(*uintptr)(unsafe.Pointer(next + sys.PtrSize)) = *dst + if np >= buf.end { + wbBufFlush(dst, src) + } + *dst = src +} Index: libgo/go/runtime/signal_gccgo.go =================================================================== --- libgo/go/runtime/signal_gccgo.go (revision 256262) +++ libgo/go/runtime/signal_gccgo.go (working copy) @@ -46,11 +46,6 @@ func kill(pid _pid_t, sig uint32) int32 //extern setitimer func setitimer(which int32, new *_itimerval, old *_itimerval) int32 -type sigTabT struct { - flags int32 - name string -} - type sigctxt struct { info *_siginfo_t ctxt unsafe.Pointer Index: libgo/go/runtime/traceback_gccgo.go =================================================================== --- libgo/go/runtime/traceback_gccgo.go (revision 256262) +++ libgo/go/runtime/traceback_gccgo.go (working copy) @@ -52,7 +52,7 @@ func c_callers(skip int32, locbuf *locat // callers returns a stack trace of the current goroutine. // The gc version of callers takes []uintptr, but we take []location. func callers(skip int, locbuf []location) int { - n := c_callers(int32(skip), &locbuf[0], int32(len(locbuf)), false) + n := c_callers(int32(skip)+1, &locbuf[0], int32(len(locbuf)), false) return int(n) } @@ -156,7 +156,7 @@ func goroutineheader(gp *g) { if waitfor >= 1 { print(", ", waitfor, " minutes") } - if gp.lockedm != nil { + if gp.lockedm != 0 { print(", locked to thread") } print("]:\n")