This patch to the Go frontend and libgo implements the abi.FuncPCABI0 and abi.FuncPCABIInternal functions. The Go 1.18 standard library uses an internal/abi package with two functions that are implemented in the compiler. This patch implements them in the gofrontend, to support the upcoming update to 1.18. For the gofrontend, which uses the platform ABI, the functions behave identically. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline.
Ian patc
56fa431758bcc37c4dade7b2d8d38feb0c59097e diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index f78561c3483..5f4adf9d0e7 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -61f7cf4b9db0587ff099aa36832a355b90ee1bf9 +262cb89fd5ed82ab135a3933b2ddf4eb67683149 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 79702821336..1e6890a3cc5 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -12177,6 +12177,50 @@ Call_expression::intrinsify(Gogo* gogo, return Runtime::make_call(code, loc, 3, a1, a2, a3); } } + else if (package == "internal/abi") + { + if ((name == "FuncPCABI0" || name == "FuncPCABIInternal") + && this->args_ != NULL + && this->args_->size() == 1) + { + // We expect to see a conversion from the expression to "any". + Expression* expr = this->args_->front(); + Type_conversion_expression* tce = expr->conversion_expression(); + if (tce != NULL) + expr = tce->expr(); + Func_expression* fe = expr->func_expression(); + Interface_field_reference_expression* interface_method = + expr->interface_field_reference_expression(); + if (fe != NULL) + { + Named_object* no = fe->named_object(); + Expression* ref = Expression::make_func_code_reference(no, loc); + Type* uintptr_type = Type::lookup_integer_type("uintptr"); + return Expression::make_cast(uintptr_type, ref, loc); + } + else if (interface_method != NULL) + return interface_method->get_function(); + else + { + expr = this->args_->front(); + go_assert(expr->type()->interface_type() != NULL + && expr->type()->interface_type()->is_empty()); + expr = Expression::make_interface_info(expr, + INTERFACE_INFO_OBJECT, + loc); + // Trust that this is a function type, which means that + // it is a direct iface type and we can use EXPR + // directly. The backend representation of this + // function is a pointer to a struct whose first field + // is the actual function to call. + Type* pvoid = Type::make_pointer_type(Type::make_void_type()); + Type* pfntype = Type::make_pointer_type(pvoid); + Expression* ref = make_unsafe_cast(pfntype, expr, loc); + return Expression::make_dereference(ref, NIL_CHECK_NOT_NEEDED, + loc); + } + } + } return NULL; } diff --git a/libgo/go/internal/abi/abi.go b/libgo/go/internal/abi/abi.go new file mode 100644 index 00000000000..c4a108847ca --- /dev/null +++ b/libgo/go/internal/abi/abi.go @@ -0,0 +1,35 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package abi + +// FuncPC* intrinsics. +// +// CAREFUL: In programs with plugins, FuncPC* can return different values +// for the same function (because there are actually multiple copies of +// the same function in the address space). To be safe, don't use the +// results of this function in any == expression. It is only safe to +// use the result as an address at which to start executing code. + +// FuncPCABI0 returns the entry PC of the function f, which must be a +// direct reference of a function defined as ABI0. Otherwise it is a +// compile-time error. +// +// Implemented as a compile intrinsic. +func FuncPCABI0(f any) uintptr { + // The compiler should remove all calls. + panic("FuncPCABI0") +} + +// FuncPCABIInternal returns the entry PC of the function f. If f is a +// direct reference of a function, it must be defined as ABIInternal. +// Otherwise it is a compile-time error. If f is not a direct reference +// of a defined function, it assumes that f is a func value. Otherwise +// the behavior is undefined. +// +// Implemented as a compile intrinsic. +func FuncPCABIInternal(f any) uintptr { + // The compiler should remove all calls. + panic("FuncPCABIInternal") +} diff --git a/libgo/go/runtime/proc.go b/libgo/go/runtime/proc.go index 05342905ff1..343f13b40f0 100644 --- a/libgo/go/runtime/proc.go +++ b/libgo/go/runtime/proc.go @@ -5,6 +5,7 @@ package runtime import ( + "internal/abi" "internal/cpu" "runtime/internal/atomic" "runtime/internal/sys" @@ -4243,11 +4244,11 @@ func _GC() { _GC() } func _LostSIGPROFDuringAtomic64() { _LostSIGPROFDuringAtomic64() } func _VDSO() { _VDSO() } -var _SystemPC = funcPC(_System) -var _ExternalCodePC = funcPC(_ExternalCode) -var _LostExternalCodePC = funcPC(_LostExternalCode) -var _GCPC = funcPC(_GC) -var _LostSIGPROFDuringAtomic64PC = funcPC(_LostSIGPROFDuringAtomic64) +var _SystemPC = abi.FuncPCABIInternal(_System) +var _ExternalCodePC = abi.FuncPCABIInternal(_ExternalCode) +var _LostExternalCodePC = abi.FuncPCABIInternal(_LostExternalCode) +var _GCPC = abi.FuncPCABIInternal(_GC) +var _LostSIGPROFDuringAtomic64PC = abi.FuncPCABIInternal(_LostSIGPROFDuringAtomic64) // Called if we receive a SIGPROF signal. // Called by the signal handler, may run during STW. diff --git a/libgo/libgo-packages.txt b/libgo/libgo-packages.txt index 4fc8c843f02..f3097dc0a6a 100644 --- a/libgo/libgo-packages.txt +++ b/libgo/libgo-packages.txt @@ -113,6 +113,7 @@ image/internal/imageutil image/jpeg image/png index/suffixarray +internal/abi internal/buildcfg internal/bytealg internal/cfg