From patchwork Thu Oct 20 18:51:38 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 684739 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3t0Hwj4sM1z9sxS for ; Fri, 21 Oct 2016 05:52:05 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=Kykyg1Sj; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; q= dns; s=default; b=Gsp0t5zcDsqdgg0PhDSISLGG9cpkoQ1N4EHgVYMpO8V3ru DmghmLDUranLhDeMXTm35G/iGW63RHvnlv1gLzPlAdHUbIWRIBw+WRswQ23Q/KSV DM1zQ4fCs241pKa169+i4jmQQvzC37jxMKzTSxId3IxNQdHNUYaSk4A6oa1c4= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; s= default; bh=Y5s+3/aV7nAxZbKyiorvgO+nBdc=; b=Kykyg1SjB9gM+7WQGfZD aMak+3IA6NkOwOv7KhBG+2JkvEPTKQ7P5mFYse7lJiGpVuNr/+ynj5kAY+4VWSvK jezSSHS3TrdcCcM1mFBAHfKpkEUAfTDWLa/bUvJJdx0zX1KkNvkPP3FovMUMjNan 74rc7lx+u/m9GcAgoGu/ORU= Received: (qmail 109444 invoked by alias); 20 Oct 2016 18:51:52 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 109423 invoked by uid 89); 20 Oct 2016 18:51:51 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=2.0 required=5.0 tests=AWL, BAYES_50, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, RCVD_IN_SORBS_SPAM, SPF_PASS autolearn=no version=3.3.2 spammy=HTo:D*googlegroups.com, cap, srcdir, inter X-HELO: mail-it0-f48.google.com Received: from mail-it0-f48.google.com (HELO mail-it0-f48.google.com) (209.85.214.48) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 20 Oct 2016 18:51:41 +0000 Received: by mail-it0-f48.google.com with SMTP id 139so176586711itm.1 for ; Thu, 20 Oct 2016 11:51:41 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=D0Asxm1oU34P2RXDstoTTAVoynV6GrQeBv054CmrqI4=; b=PavyBhg32HFrGxhsfA2nVxCrXcp1Phe876/EWNUIH9FQCb620//MsmKC4oMYm/hZFO Se1wLs837I1KYLJTQJzaspomI4Q/BF6dIFPOsZkM1Zt0zO9xivIsNU7WKmlvIhkZ7NMv Qswk2LfrfwBwem+XM0B40CGLohQE8gD4KWIEdDNi85mfDlbhylYz68aiFaGHzsXwSJOk a+FMd87vGo0/PjrUZlr0uWMo63UTmz0iO7dOn8EtN10ZGEufMzRNFwO7TZQcYOsQElMM 7iHEEOpgyywpvqj1WPgf69waY7fpGTGtPmdoSs53HX1etsVCTmW5gyj8IFB0p2Y5TxgX 7aKQ== X-Gm-Message-State: ABUngvdEexq0Ur7MmsS/hfZYoF1eWWpZJ1bt+OZqTCntoOAyZmrENeuFa2EYW4OXhpdLOfkjn0QCgWpi3M6Bmg== X-Received: by 10.107.157.14 with SMTP id g14mr2781568ioe.70.1476989499052; Thu, 20 Oct 2016 11:51:39 -0700 (PDT) MIME-Version: 1.0 Received: by 10.79.154.155 with HTTP; Thu, 20 Oct 2016 11:51:38 -0700 (PDT) From: Ian Lance Taylor Date: Thu, 20 Oct 2016 11:51:38 -0700 Message-ID: Subject: libgo patch committed: Rewrite interface code into Go To: gcc-patches , "gofrontend-dev@googlegroups.com" This patch to libgo rewrites the interface code from C to Go. I started to copy the Go 1.7 interface code, but the gc and gccgo representations of interfaces are too different. So instead I rewrote the gccgo interface code from C to Go. The code is largely the same as it was, but the names are more like those used in the gc runtime. I also copied over the string comparison functions, and tweaked the compiler to use eqstring when comparing strings for equality. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian Index: gcc/go/gofrontend/MERGE =================================================================== --- gcc/go/gofrontend/MERGE (revision 241347) +++ gcc/go/gofrontend/MERGE (working copy) @@ -1,4 +1,4 @@ -5346c7d15362a16efa0defaaeca63b1fce1c1523 +14dc8052a09ad0a2226e64ab6b5af69c6923b830 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. Index: gcc/go/gofrontend/escape.cc =================================================================== --- gcc/go/gofrontend/escape.cc (revision 241341) +++ gcc/go/gofrontend/escape.cc (working copy) @@ -1874,7 +1874,7 @@ Escape_analysis_assign::assign(Node* dst case Runtime::IFACEI2T2P: case Runtime::IFACEE2T2: case Runtime::IFACEI2T2: - case Runtime::CONVERT_INTERFACE: + case Runtime::REQUIREITAB: // All versions of interface conversion that might result // from a type assertion. Some of these are the result of // a tuple type assertion statement and may not be covered @@ -2633,7 +2633,7 @@ Escape_analysis_flood::flood(Level level case Runtime::CONCATSTRING5: case Runtime::CONSTRUCT_MAP: case Runtime::INTSTRING: - case Runtime::CONVERT_INTERFACE: + case Runtime::REQUIREITAB: // All runtime calls that involve allocation of memory // except new. Runtime::NEW gets lowered into an // allocation expression. Index: gcc/go/gofrontend/expressions.cc =================================================================== --- gcc/go/gofrontend/expressions.cc (revision 241341) +++ gcc/go/gofrontend/expressions.cc (working copy) @@ -323,9 +323,8 @@ Expression::convert_interface_to_interfa if (for_type_guard) { // A type assertion fails when converting a nil interface. - first_field = - Runtime::make_call(Runtime::ASSERT_INTERFACE, location, 2, - lhs_type_expr, rhs_type_expr); + first_field = Runtime::make_call(Runtime::ASSERTITAB, location, 2, + lhs_type_expr, rhs_type_expr); } else if (lhs_is_empty) { @@ -337,9 +336,8 @@ Expression::convert_interface_to_interfa { // A conversion to a non-empty interface may fail, but unlike a // type assertion converting nil will always succeed. - first_field = - Runtime::make_call(Runtime::CONVERT_INTERFACE, location, 2, - lhs_type_expr, rhs_type_expr); + first_field = Runtime::make_call(Runtime::REQUIREITAB, location, 2, + lhs_type_expr, rhs_type_expr); } // The second field is simply the object pointer. @@ -370,7 +368,7 @@ Expression::convert_interface_to_type(Ty Expression* rhs_inter_expr = Expression::make_type_descriptor(rhs_type, location); - Expression* check_iface = Runtime::make_call(Runtime::CHECK_INTERFACE_TYPE, + Expression* check_iface = Runtime::make_call(Runtime::ASSERTI2T, location, 3, lhs_type_expr, rhs_descriptor, rhs_inter_expr); @@ -1290,7 +1288,10 @@ Func_descriptor_expression::do_get_backe && !no->func_declaration_value()->asm_name().empty() && Linemap::is_predeclared_location(no->location())) { - var_name = no->func_declaration_value()->asm_name() + "_descriptor"; + if (no->func_declaration_value()->asm_name().substr(0, 8) != "runtime.") + var_name = no->func_declaration_value()->asm_name() + "_descriptor"; + else + var_name = no->func_declaration_value()->asm_name() + "$descriptor"; is_descriptor = true; } else @@ -6196,9 +6197,18 @@ Expression::comparison(Translate_context if (left_type->is_string_type() && right_type->is_string_type()) { - left = Runtime::make_call(Runtime::STRCMP, location, 2, - left, right); - right = zexpr; + if (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ) + { + left = Runtime::make_call(Runtime::EQSTRING, location, 2, + left, right); + right = Expression::make_boolean(true, location); + } + else + { + left = Runtime::make_call(Runtime::CMPSTRING, location, 2, + left, right); + right = zexpr; + } } else if ((left_type->interface_type() != NULL && right_type->interface_type() == NULL @@ -6230,11 +6240,12 @@ Expression::comparison(Translate_context Expression::make_type_descriptor(right_type, location); left = Runtime::make_call((left_type->interface_type()->is_empty() - ? Runtime::EMPTY_INTERFACE_VALUE_COMPARE - : Runtime::INTERFACE_VALUE_COMPARE), + ? Runtime::EFACEVALEQ + : Runtime::IFACEVALEQ), location, 3, left, descriptor, pointer_arg); - right = zexpr; + go_assert(op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ); + right = Expression::make_boolean(true, location); } else if (left_type->interface_type() != NULL && right_type->interface_type() != NULL) @@ -6242,25 +6253,25 @@ Expression::comparison(Translate_context Runtime::Function compare_function; if (left_type->interface_type()->is_empty() && right_type->interface_type()->is_empty()) - compare_function = Runtime::EMPTY_INTERFACE_COMPARE; + compare_function = Runtime::EFACEEQ; else if (!left_type->interface_type()->is_empty() && !right_type->interface_type()->is_empty()) - compare_function = Runtime::INTERFACE_COMPARE; + compare_function = Runtime::IFACEEQ; else { if (left_type->interface_type()->is_empty()) { - go_assert(op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ); std::swap(left_type, right_type); std::swap(left, right); } go_assert(!left_type->interface_type()->is_empty()); go_assert(right_type->interface_type()->is_empty()); - compare_function = Runtime::INTERFACE_EMPTY_COMPARE; + compare_function = Runtime::IFACEEFACEEQ; } left = Runtime::make_call(compare_function, location, 2, left, right); - right = zexpr; + go_assert(op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ); + right = Expression::make_boolean(true, location); } if (left_type->is_nil_type() Index: gcc/go/gofrontend/runtime.def =================================================================== --- gcc/go/gofrontend/runtime.def (revision 241341) +++ gcc/go/gofrontend/runtime.def (working copy) @@ -50,8 +50,11 @@ DEF_GO_RUNTIME(CONCATSTRING4, "runtime.c DEF_GO_RUNTIME(CONCATSTRING5, "runtime.concatstring5", P2(POINTER, ARRAY5STRING), R1(STRING)) +// Compare two strings for equality. +DEF_GO_RUNTIME(EQSTRING, "runtime.eqstring", P2(STRING, STRING), R1(BOOL)) + // Compare two strings. -DEF_GO_RUNTIME(STRCMP, "__go_strcmp", P2(STRING, STRING), R1(INT)) +DEF_GO_RUNTIME(CMPSTRING, "runtime.cmpstring", P2(STRING, STRING), R1(INT)) // Take a slice of a string. DEF_GO_RUNTIME(STRING_SLICE, "__go_string_slice", P3(STRING, INT, INT), @@ -259,22 +262,27 @@ DEF_GO_RUNTIME(IFACEE2T2, "runtime.iface DEF_GO_RUNTIME(IFACEI2T2, "runtime.ifaceI2T2", P3(TYPE, IFACE, POINTER), R1(BOOL)) -// A type assertion from one interface type to another. This is -// used for a type assertion. -DEF_GO_RUNTIME(ASSERT_INTERFACE, "__go_assert_interface", P2(TYPE, TYPE), R1(POINTER)) - -// Convert one interface type to another. This is used for an -// assignment. -DEF_GO_RUNTIME(CONVERT_INTERFACE, "__go_convert_interface", P2(TYPE, TYPE), +// Return the interface method table for the second type converted to +// the first type which is a (possibly empty) interface type. Panics +// if the second type is nil (indicating a nil interface value) or if +// the conversion is not possible. Used for type assertions. This is +// like REQUIREITAB, but for type assertions. +DEF_GO_RUNTIME(ASSERTITAB, "runtime.assertitab", P2(TYPE, TYPE), R1(POINTER)) + +// Return the interface method table for the second type converted to +// the first type, which is a non-empty interface type. Return nil if +// the second type is nil, indicating a nil interface value. Panics +// if the conversion is not possible. Used for assignments. This is +// like ASSERTITAB, but for assignments. +DEF_GO_RUNTIME(REQUIREITAB, "runtime.requireitab", P2(TYPE, TYPE), R1(POINTER)) // Check whether an interface type may be converted to a // non-interface type. -DEF_GO_RUNTIME(CHECK_INTERFACE_TYPE, "__go_check_interface_type", - P3(TYPE, TYPE, TYPE), R0()) +DEF_GO_RUNTIME(ASSERTI2T, "runtime.assertI2T", P3(TYPE, TYPE, TYPE), R0()) -// Return whether we can convert an interface type to a type. -DEF_GO_RUNTIME(IFACEI2TP, "runtime.ifaceI2Tp", P2(TYPE, TYPE), R1(BOOL)) +// Return whether we can convert a type to an interface type. +DEF_GO_RUNTIME(IFACET2IP, "runtime.ifaceT2Ip", P2(TYPE, TYPE), R1(BOOL)) // Get the type descriptor of an empty interface. DEF_GO_RUNTIME(EFACETYPE, "runtime.efacetype", P1(EFACE), R1(TYPE)) @@ -287,25 +295,22 @@ DEF_GO_RUNTIME(IFACETYPE, "runtime.iface DEF_GO_RUNTIME(IFACETYPEEQ, "runtime.ifacetypeeq", P2(TYPE, TYPE), R1(BOOL)) // Compare two empty interface values. -DEF_GO_RUNTIME(EMPTY_INTERFACE_COMPARE, "__go_empty_interface_compare", - P2(EFACE, EFACE), R1(INT)) +DEF_GO_RUNTIME(EFACEEQ, "runtime.efaceeq", P2(EFACE, EFACE), R1(BOOL)) // Compare an empty interface value to a non-interface value. -DEF_GO_RUNTIME(EMPTY_INTERFACE_VALUE_COMPARE, - "__go_empty_interface_value_compare", - P3(EFACE, TYPE, POINTER), R1(INT)) +DEF_GO_RUNTIME(EFACEVALEQ, "runtime.efacevaleq", P3(EFACE, TYPE, POINTER), + R1(BOOL)) // Compare two non-empty interface values. -DEF_GO_RUNTIME(INTERFACE_COMPARE, "__go_interface_compare", - P2(IFACE, IFACE), R1(INT)) +DEF_GO_RUNTIME(IFACEEQ, "runtime.ifaceeq", P2(IFACE, IFACE), R1(BOOL)) // Compare a non-empty interface value to a non-interface value. -DEF_GO_RUNTIME(INTERFACE_VALUE_COMPARE, "__go_interface_value_compare", - P3(IFACE, TYPE, POINTER), R1(INT)) +DEF_GO_RUNTIME(IFACEVALEQ, "runtime.ifacevaleq", P3(IFACE, TYPE, POINTER), + R1(BOOL)) // Compare a non-empty interface value to an interface value. -DEF_GO_RUNTIME(INTERFACE_EMPTY_COMPARE, "__go_interface_empty_compare", - P2(IFACE, EFACE), R1(INT)) +DEF_GO_RUNTIME(IFACEEFACEEQ, "runtime.ifaceefaceeq", P2(IFACE, EFACE), + R1(BOOL)) // Lock the printer (for print/println). Index: gcc/go/gofrontend/statements.cc =================================================================== --- gcc/go/gofrontend/statements.cc (revision 241341) +++ gcc/go/gofrontend/statements.cc (working copy) @@ -3894,7 +3894,7 @@ Type_case_clauses::Type_case_clause::low else cond = Runtime::make_call((type->interface_type() == NULL ? Runtime::IFACETYPEEQ - : Runtime::IFACEI2TP), + : Runtime::IFACET2IP), loc, 2, Expression::make_type_descriptor(type, loc), ref); Index: gcc/go/gofrontend/types.cc =================================================================== --- gcc/go/gofrontend/types.cc (revision 241341) +++ gcc/go/gofrontend/types.cc (working copy) @@ -1710,13 +1710,13 @@ Type::type_functions(Gogo* gogo, Named_t case Type::TYPE_INTERFACE: if (this->interface_type()->is_empty()) { - hash_fnname = "__go_type_hash_empty_interface"; - equal_fnname = "__go_type_equal_empty_interface"; + hash_fnname = "runtime.nilinterhash"; + equal_fnname = "runtime.nilinterequal"; } else { - hash_fnname = "__go_type_hash_interface"; - equal_fnname = "__go_type_equal_interface"; + hash_fnname = "runtime.interhash"; + equal_fnname = "runtime.interequal"; } break; Index: libgo/Makefile.am =================================================================== --- libgo/Makefile.am (revision 241341) +++ libgo/Makefile.am (working copy) @@ -430,26 +430,17 @@ endif runtime_files = \ runtime/go-append.c \ runtime/go-assert.c \ - runtime/go-assert-interface.c \ runtime/go-breakpoint.c \ runtime/go-caller.c \ runtime/go-callers.c \ - runtime/go-can-convert-interface.c \ runtime/go-cdiv.c \ runtime/go-cgo.c \ - runtime/go-check-interface.c \ runtime/go-construct-map.c \ - runtime/go-convert-interface.c \ runtime/go-copy.c \ runtime/go-defer.c \ runtime/go-deferred-recover.c \ - runtime/go-eface-compare.c \ - runtime/go-eface-val-compare.c \ runtime/go-ffi.c \ runtime/go-fieldtrack.c \ - runtime/go-interface-compare.c \ - runtime/go-interface-eface-compare.c \ - runtime/go-interface-val-compare.c \ runtime/go-make-slice.c \ runtime/go-matherr.c \ runtime/go-memclr.c \ @@ -466,13 +457,10 @@ runtime_files = \ runtime/go-runtime-error.c \ runtime/go-setenv.c \ runtime/go-signal.c \ - runtime/go-strcmp.c \ runtime/go-strslice.c \ runtime/go-type-complex.c \ - runtime/go-type-eface.c \ runtime/go-type-float.c \ runtime/go-type-identity.c \ - runtime/go-type-interface.c \ runtime/go-type-string.c \ runtime/go-typedesc-equal.c \ runtime/go-unsafe-new.c \ @@ -500,10 +488,8 @@ runtime_files = \ $(runtime_thread_files) \ runtime/yield.c \ $(rtems_task_variable_add_file) \ - go-iface.c \ lfstack.c \ malloc.c \ - reflect.c \ runtime1.c \ sigqueue.c \ $(runtime_getncpu_file) @@ -518,10 +504,6 @@ malloc.c: $(srcdir)/runtime/malloc.goc g ./goc2c $< > $@.tmp mv -f $@.tmp $@ -reflect.c: $(srcdir)/runtime/reflect.goc goc2c - ./goc2c $< > $@.tmp - mv -f $@.tmp $@ - runtime1.c: $(srcdir)/runtime/runtime1.goc goc2c ./goc2c $< > $@.tmp mv -f $@.tmp $@ Index: libgo/go/runtime/alg.go =================================================================== --- libgo/go/runtime/alg.go (revision 0) +++ libgo/go/runtime/alg.go (working copy) @@ -0,0 +1,204 @@ +// Copyright 2014 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 runtime + +import ( + "runtime/internal/sys" + "unsafe" +) + +// For gccgo, use go:linkname to rename compiler-called functions to +// themselves, so that the compiler will export them. +// +//go:linkname interhash runtime.interhash +//go:linkname nilinterhash runtime.nilinterhash +//go:linkname interequal runtime.interequal +//go:linkname nilinterequal runtime.nilinterequal +//go:linkname efaceeq runtime.efaceeq +//go:linkname ifaceeq runtime.ifaceeq +//go:linkname ifacevaleq runtime.ifacevaleq +//go:linkname ifaceefaceeq runtime.ifaceefaceeq +//go:linkname efacevaleq runtime.efacevaleq +//go:linkname eqstring runtime.eqstring +//go:linkname cmpstring runtime.cmpstring + +const ( + c0 = uintptr((8-sys.PtrSize)/4*2860486313 + (sys.PtrSize-4)/4*33054211828000289) + c1 = uintptr((8-sys.PtrSize)/4*3267000013 + (sys.PtrSize-4)/4*23344194077549503) +) + +func interhash(p unsafe.Pointer, h uintptr, size uintptr) uintptr { + a := (*iface)(p) + tab := a.tab + if tab == nil { + return h + } + t := *(**_type)(tab) + fn := t.hashfn + if fn == nil { + panic(errorString("hash of unhashable type " + *t.string)) + } + if isDirectIface(t) { + return c1 * fn(unsafe.Pointer(&a.data), h^c0, t.size) + } else { + return c1 * fn(a.data, h^c0, t.size) + } +} + +func nilinterhash(p unsafe.Pointer, h uintptr, size uintptr) uintptr { + a := (*eface)(p) + t := a._type + if t == nil { + return h + } + fn := t.hashfn + if fn == nil { + panic(errorString("hash of unhashable type " + *t.string)) + } + if isDirectIface(t) { + return c1 * fn(unsafe.Pointer(&a.data), h^c0, t.size) + } else { + return c1 * fn(a.data, h^c0, t.size) + } +} + +func interequal(p, q unsafe.Pointer, size uintptr) bool { + return ifaceeq(*(*iface)(p), *(*iface)(q)) +} + +func nilinterequal(p, q unsafe.Pointer, size uintptr) bool { + return efaceeq(*(*eface)(p), *(*eface)(q)) +} + +func efaceeq(x, y eface) bool { + t := x._type + if !eqtype(t, y._type) { + return false + } + if t == nil { + return true + } + eq := t.equalfn + if eq == nil { + panic(errorString("comparing uncomparable type " + *t.string)) + } + if isDirectIface(t) { + return x.data == y.data + } + return eq(x.data, y.data, t.size) +} + +func ifaceeq(x, y iface) bool { + xtab := x.tab + if xtab == nil && y.tab == nil { + return true + } + if xtab == nil || y.tab == nil { + return false + } + t := *(**_type)(xtab) + if !eqtype(t, *(**_type)(y.tab)) { + return false + } + eq := t.equalfn + if eq == nil { + panic(errorString("comparing uncomparable type " + *t.string)) + } + if isDirectIface(t) { + return x.data == y.data + } + return eq(x.data, y.data, t.size) +} + +func ifacevaleq(x iface, t *_type, p unsafe.Pointer) bool { + if x.tab == nil { + return false + } + xt := *(**_type)(x.tab) + if !eqtype(xt, t) { + return false + } + eq := t.equalfn + if eq == nil { + panic(errorString("comparing uncomparable type " + *t.string)) + } + if isDirectIface(t) { + return x.data == p + } + return eq(x.data, p, t.size) +} + +func ifaceefaceeq(x iface, y eface) bool { + if x.tab == nil && y._type == nil { + return true + } + if x.tab == nil || y._type == nil { + return false + } + xt := *(**_type)(x.tab) + if !eqtype(xt, y._type) { + return false + } + eq := xt.equalfn + if eq == nil { + panic(errorString("comparing uncomparable type " + *xt.string)) + } + if isDirectIface(xt) { + return x.data == y.data + } + return eq(x.data, y.data, xt.size) +} + +func efacevaleq(x eface, t *_type, p unsafe.Pointer) bool { + if x._type == nil { + return false + } + if !eqtype(x._type, t) { + return false + } + eq := t.equalfn + if eq == nil { + panic(errorString("comparing uncomparable type " + *t.string)) + } + if isDirectIface(t) { + return x.data == p + } + return eq(x.data, p, t.size) +} + +func eqstring(x, y string) bool { + a := stringStructOf(&x) + b := stringStructOf(&y) + if a.len != b.len { + return false + } + return memcmp(unsafe.Pointer(a.str), unsafe.Pointer(b.str), uintptr(a.len)) == 0 +} + +func cmpstring(x, y string) int { + a := stringStructOf(&x) + b := stringStructOf(&y) + l := a.len + if l > b.len { + l = b.len + } + i := memcmp(unsafe.Pointer(a.str), unsafe.Pointer(b.str), uintptr(l)) + if i != 0 { + return int(i) + } + if a.len < b.len { + return -1 + } else if a.len > b.len { + return 1 + } + return 0 +} + +// Force the creation of function descriptors for equality and hash +// functions. These will be referenced directly by the compiler. +var _ = interhash +var _ = interequal +var _ = nilinterhash +var _ = nilinterequal Index: libgo/go/runtime/iface.go =================================================================== --- libgo/go/runtime/iface.go (revision 0) +++ libgo/go/runtime/iface.go (working copy) @@ -0,0 +1,334 @@ +// Copyright 2014 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 runtime + +import ( + "unsafe" +) + +// For gccgo, use go:linkname to rename compiler-called functions to +// themselves, so that the compiler will export them. +// +//go:linkname requireitab runtime.requireitab +//go:linkname assertitab runtime.assertitab +//go:linkname assertI2T runtime.assertI2T +//go:linkname ifacetypeeq runtime.ifacetypeeq +//go:linkname efacetype runtime.efacetype +//go:linkname ifacetype runtime.ifacetype +//go:linkname ifaceE2E2 runtime.ifaceE2E2 +//go:linkname ifaceI2E2 runtime.ifaceI2E2 +//go:linkname ifaceE2I2 runtime.ifaceE2I2 +//go:linkname ifaceI2I2 runtime.ifaceI2I2 +//go:linkname ifaceE2T2P runtime.ifaceE2T2P +//go:linkname ifaceI2T2P runtime.ifaceI2T2P +//go:linkname ifaceE2T2 runtime.ifaceE2T2 +//go:linkname ifaceI2T2 runtime.ifaceI2T2 +//go:linkname ifaceT2Ip runtime.ifaceT2Ip +// Temporary for C code to call: +//go:linkname getitab runtime.getitab + +// The gccgo itab structure is different than the gc one. +// +// Both gccgo and gc represent empty interfaces the same way: +// a two field struct, where the first field points to a type descriptor +// (a *_type) and the second field is the data pointer. +// +// Non-empty interfaces are also two-field structs, and the second +// field is the data pointer. However, for gccgo, the first field, the +// itab field, is different. The itab field points to the interface +// method table, which is the implemention of a specific interface +// type for a specific dynamic non-interface type. An interface +// method table is a list of pointer values. The first pointer is the +// type descriptor (a *_type) for the dynamic type. The subsequent +// pointers are pointers to function code, which implement the methods +// required by the interface. The pointers are sorted by name. +// +// The method pointers in the itab are C function pointers, not Go +// function pointers; they may be called directly, and they have no +// closures. The receiver is always passed as a pointer, and it is +// always the same pointer stored in the interface value. A value +// method starts by copying the receiver value out of the pointer into +// a local variable. +// +// A method call on an interface value is by definition calling a +// method at a known index m in the list of methods. Given a non-empty +// interface value i, the call i.m(args) looks like +// i.itab[m+1](i.iface, args) + +// Both an empty interface and a non-empty interface have a data +// pointer field. The meaning of this field is determined by the +// kindDirectIface bit in the `kind` field of the type descriptor of +// the value stored in the interface. If kindDirectIface is set, then +// the data pointer field in the interface value is exactly the value +// stored in the interface. Otherwise, the data pointer field is a +// pointer to memory that holds the value. It follows from this that +// kindDirectIface can only be set for a type whose representation is +// simply a pointer. In the current gccgo implementation, this is set +// only for pointer types (including unsafe.Pointer). In the future it +// could also be set for other types: channels, maps, functions, +// single-field structs and single-element arrays whose single field +// is simply a pointer. + +// For a nil interface value both fields in the interface struct are nil. + +// Return the interface method table for a value of type rhs converted +// to an interface of type lhs. +func getitab(lhs, rhs *_type, canfail bool) unsafe.Pointer { + if rhs == nil { + return nil + } + + if lhs.kind&kindMask != kindInterface { + throw("getitab called for non-interface type") + } + + lhsi := (*interfacetype)(unsafe.Pointer(lhs)) + + if len(lhsi.methods) == 0 { + throw("getitab called for empty interface type") + } + + if rhs.uncommontype == nil || len(rhs.methods) == 0 { + if canfail { + return nil + } + panic(&TypeAssertionError{"", *rhs.string, *lhs.string, *lhsi.methods[0].name}) + } + + methods := make([]unsafe.Pointer, len(lhsi.methods)+1) + methods[0] = unsafe.Pointer(rhs) + + ri := 0 + for li := range lhsi.methods { + lhsMethod := &lhsi.methods[li] + var rhsMethod *method + + for { + if ri >= len(rhs.methods) { + if canfail { + return nil + } + panic(&TypeAssertionError{"", *rhs.string, *lhs.string, *lhsMethod.name}) + } + + rhsMethod = &rhs.methods[ri] + if (lhsMethod.name == rhsMethod.name || *lhsMethod.name == *rhsMethod.name) && + (lhsMethod.pkgPath == rhsMethod.pkgPath || *lhsMethod.pkgPath == *rhsMethod.pkgPath) { + break + } + + ri++ + } + + if !eqtype(lhsMethod.typ, rhsMethod.mtyp) { + if canfail { + return nil + } + panic(&TypeAssertionError{"", *rhs.string, *lhs.string, *lhsMethod.name}) + } + + methods[li+1] = unsafe.Pointer(rhsMethod.tfn) + ri++ + } + + return unsafe.Pointer(&methods[0]) +} + +// Return the interface method table for a value of type rhs converted +// to an interface of type lhs. Panics if the conversion is impossible. +func requireitab(lhs, rhs *_type) unsafe.Pointer { + return getitab(lhs, rhs, false) +} + +// Return the interface method table for a value of type rhs converted +// to an interface of type lhs. Panics if the conversion is +// impossible or if the rhs type is nil. +func assertitab(lhs, rhs *_type) unsafe.Pointer { + if rhs == nil { + panic(&TypeAssertionError{"", "", *lhs.string, ""}) + } + + if lhs.kind&kindMask != kindInterface { + throw("assertitab called for non-interface type") + } + + lhsi := (*interfacetype)(unsafe.Pointer(lhs)) + + if len(lhsi.methods) == 0 { + return unsafe.Pointer(rhs) + } + + return getitab(lhs, rhs, false) +} + +// Check whether an interface type may be converted to a non-interface +// type, panicing if not. +func assertI2T(lhs, rhs, inter *_type) { + if rhs == nil { + panic(&TypeAssertionError{"", "", *lhs.string, ""}) + } + if !eqtype(lhs, rhs) { + panic(&TypeAssertionError{*inter.string, *rhs.string, *lhs.string, ""}) + } +} + +// Compare two type descriptors for equality. +func ifacetypeeq(a, b *_type) bool { + return eqtype(a, b) +} + +// Return the type descriptor of an empty interface. +// FIXME: This should be inlined by the compiler. +func efacetype(e eface) *_type { + return e._type +} + +// Return the type descriptor of a non-empty interface. +// FIXME: This should be inlined by the compiler. +func ifacetype(i iface) *_type { + if i.tab == nil { + return nil + } + return *(**_type)(i.tab) +} + +// Convert an empty interface to an empty interface, for a comma-ok +// type assertion. +func ifaceE2E2(e eface) (eface, bool) { + return e, e._type != nil +} + +// Convert a non-empty interface to an empty interface, for a comma-ok +// type assertion. +func ifaceI2E2(i iface) (eface, bool) { + if i.tab == nil { + return eface{nil, nil}, false + } else { + return eface{*(**_type)(i.tab), i.data}, true + } +} + +// Convert an empty interface to a non-empty interface, for a comma-ok +// type assertion. +func ifaceE2I2(inter *_type, e eface) (iface, bool) { + if e._type == nil { + return iface{nil, nil}, false + } else { + itab := getitab(inter, e._type, true) + if itab == nil { + return iface{nil, nil}, false + } else { + return iface{itab, e.data}, true + } + } +} + +// Convert a non-empty interface to a non-empty interface, for a +// comma-ok type assertion. +func ifaceI2I2(inter *_type, i iface) (iface, bool) { + if i.tab == nil { + return iface{nil, nil}, false + } else { + itab := getitab(inter, *(**_type)(i.tab), true) + if itab == nil { + return iface{nil, nil}, false + } else { + return iface{itab, i.data}, true + } + } +} + +// Convert an empty interface to a pointer non-interface type. +func ifaceE2T2P(t *_type, e eface) (unsafe.Pointer, bool) { + if !eqtype(t, e._type) { + return nil, false + } else { + return e.data, true + } +} + +// Convert a non-empty interface to a pointer non-interface type. +func ifaceI2T2P(t *_type, i iface) (unsafe.Pointer, bool) { + if i.tab == nil || !eqtype(t, *(**_type)(i.tab)) { + return nil, false + } else { + return i.data, true + } +} + +// Convert an empty interface to a non-pointer non-interface type. +func ifaceE2T2(t *_type, e eface, ret unsafe.Pointer) bool { + if !eqtype(t, e._type) { + memclr(ret, t.size) + return false + } else { + typedmemmove(t, ret, e.data) + return true + } +} + +// Convert a non-empty interface to a non-pointer non-interface type. +func ifaceI2T2(t *_type, i iface, ret unsafe.Pointer) bool { + if i.tab == nil || !eqtype(t, *(**_type)(i.tab)) { + memclr(ret, t.size) + return false + } else { + typedmemmove(t, ret, i.data) + return true + } +} + +// Return whether we can convert a type to an interface type. +func ifaceT2Ip(to, from *_type) bool { + if from == nil { + return false + } + + if to.kind&kindMask != kindInterface { + throw("ifaceT2Ip called with non-interface type") + } + toi := (*interfacetype)(unsafe.Pointer(to)) + + if from.uncommontype == nil || len(from.methods) == 0 { + return len(toi.methods) == 0 + } + + ri := 0 + for li := range toi.methods { + toMethod := &toi.methods[li] + var fromMethod *method + for { + if ri >= len(from.methods) { + return false + } + + fromMethod = &from.methods[ri] + if (toMethod.name == fromMethod.name || *toMethod.name == *fromMethod.name) && + (toMethod.pkgPath == fromMethod.pkgPath || *toMethod.pkgPath == *fromMethod.pkgPath) { + break + } + + ri++ + } + + if !eqtype(fromMethod.mtyp, toMethod.typ) { + return false + } + + ri++ + } + + return true +} + +//go:linkname reflect_ifaceE2I reflect.ifaceE2I +func reflect_ifaceE2I(inter *interfacetype, e eface, dst *iface) { + t := e._type + if t == nil { + panic(TypeAssertionError{"", "", *inter.typ.string, ""}) + } + dst.tab = requireitab((*_type)(unsafe.Pointer(inter)), t) + dst.data = e.data +} Index: libgo/go/runtime/runtime2.go =================================================================== --- libgo/go/runtime/runtime2.go (revision 241341) +++ libgo/go/runtime/runtime2.go (working copy) @@ -138,11 +138,15 @@ type funcval struct { // variable-size, fn-specific data here } +// The representation of a non-empty interface. +// See comment in iface.go for more details on this struct. type iface struct { tab unsafe.Pointer data unsafe.Pointer } +// The representation of an empty interface. +// See comment in iface.go for more details on this struct. type eface struct { _type *_type data unsafe.Pointer Index: libgo/go/runtime/stubs.go =================================================================== --- libgo/go/runtime/stubs.go (revision 241341) +++ libgo/go/runtime/stubs.go (working copy) @@ -73,7 +73,6 @@ func reflect_memclr(ptr unsafe.Pointer, } // memmove copies n bytes from "from" to "to". -// in memmove_*.s //go:noescape func memmove(to, from unsafe.Pointer, n uintptr) @@ -82,6 +81,10 @@ func reflect_memmove(to, from unsafe.Poi memmove(to, from, n) } +//go:noescape +//extern __builtin_memcmp +func memcmp(a, b unsafe.Pointer, size uintptr) int32 + // exported value for testing var hashLoad = loadFactor @@ -466,3 +469,8 @@ func setMaxThreads(in int) (out int) { func atomicstorep(ptr unsafe.Pointer, new unsafe.Pointer) { atomic.StorepNoWB(noescape(ptr), new) } + +// Temporary for gccgo until we port mbarrier.go +func writebarrierptr(dst *uintptr, src uintptr) { + *dst = src +} Index: libgo/go/runtime/type.go =================================================================== --- libgo/go/runtime/type.go (revision 241341) +++ libgo/go/runtime/type.go (working copy) @@ -25,6 +25,22 @@ type _type struct { ptrToThis *_type } +// Return whether two type descriptors are equal. +// This is gccgo-specific, as gccgo, unlike gc, permits multiple +// independent descriptors for a single type. +func eqtype(t1, t2 *_type) bool { + switch { + case t1 == t2: + return true + case t1 == nil || t2 == nil: + return false + case t1.kind != t2.kind || t1.hash != t2.hash: + return false + default: + return *t1.string == *t2.string + } +} + type method struct { name *string pkgPath *string Index: libgo/runtime/go-assert-interface.c =================================================================== --- libgo/runtime/go-assert-interface.c (revision 241341) +++ libgo/runtime/go-assert-interface.c (working copy) @@ -1,45 +0,0 @@ -/* go-assert-interface.c -- interface type assertion for Go. - - Copyright 2010 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. */ - -#include "runtime.h" -#include "go-alloc.h" -#include "go-assert.h" -#include "go-panic.h" -#include "go-type.h" -#include "interface.h" - -/* This is called by the compiler to implement a type assertion from - one interface type to another. This returns the value that should - go in the first field of the result tuple. The result may be an - empty or a non-empty interface. */ - -const void * -__go_assert_interface (const struct __go_type_descriptor *lhs_descriptor, - const struct __go_type_descriptor *rhs_descriptor) -{ - const struct __go_interface_type *lhs_interface; - - if (rhs_descriptor == NULL) - { - struct __go_empty_interface panic_arg; - - /* A type assertion is not permitted with a nil interface. */ - - runtime_newTypeAssertionError (NULL, NULL, lhs_descriptor->__reflection, - NULL, &panic_arg); - __go_panic (panic_arg); - } - - /* A type assertion to an empty interface just returns the object - descriptor. */ - - __go_assert ((lhs_descriptor->__code & GO_CODE_MASK) == GO_INTERFACE); - lhs_interface = (const struct __go_interface_type *) lhs_descriptor; - if (lhs_interface->__methods.__count == 0) - return rhs_descriptor; - - return __go_convert_interface_2 (lhs_descriptor, rhs_descriptor, 0); -} Index: libgo/runtime/go-can-convert-interface.c =================================================================== --- libgo/runtime/go-can-convert-interface.c (revision 241341) +++ libgo/runtime/go-can-convert-interface.c (working copy) @@ -1,78 +0,0 @@ -/* go-can-convert-interface.c -- can we convert to an interface? - - Copyright 2009 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. */ - -#include "runtime.h" -#include "go-assert.h" -#include "go-string.h" -#include "go-type.h" -#include "interface.h" - -/* Return whether we can convert from the type in FROM_DESCRIPTOR to - the interface in TO_DESCRIPTOR. This is used for type - switches. */ - -_Bool -__go_can_convert_to_interface ( - const struct __go_type_descriptor *to_descriptor, - const struct __go_type_descriptor *from_descriptor) -{ - const struct __go_interface_type *to_interface; - int to_method_count; - const struct __go_interface_method *to_method; - const struct __go_uncommon_type *from_uncommon; - int from_method_count; - const struct __go_method *from_method; - int i; - - /* In a type switch FROM_DESCRIPTOR can be NULL. */ - if (from_descriptor == NULL) - return 0; - - __go_assert ((to_descriptor->__code & GO_CODE_MASK) == GO_INTERFACE); - to_interface = (const struct __go_interface_type *) to_descriptor; - to_method_count = to_interface->__methods.__count; - to_method = ((const struct __go_interface_method *) - to_interface->__methods.__values); - - from_uncommon = from_descriptor->__uncommon; - if (from_uncommon == NULL) - { - from_method_count = 0; - from_method = NULL; - } - else - { - from_method_count = from_uncommon->__methods.__count; - from_method = ((const struct __go_method *) - from_uncommon->__methods.__values); - } - - for (i = 0; i < to_method_count; ++i) - { - while (from_method_count > 0 - && (!__go_ptr_strings_equal (from_method->__name, - to_method->__name) - || !__go_ptr_strings_equal (from_method->__pkg_path, - to_method->__pkg_path))) - { - ++from_method; - --from_method_count; - } - - if (from_method_count == 0) - return 0; - - if (!__go_type_descriptors_equal (from_method->__mtype, - to_method->__type)) - return 0; - - ++to_method; - ++from_method; - --from_method_count; - } - - return 1; -} Index: libgo/runtime/go-cgo.c =================================================================== --- libgo/runtime/go-cgo.c (revision 241341) +++ libgo/runtime/go-cgo.c (working copy) @@ -6,7 +6,6 @@ #include "runtime.h" #include "go-alloc.h" -#include "interface.h" #include "go-panic.h" #include "go-type.h" @@ -170,7 +169,8 @@ _cgo_panic (const char *p) intgo len; unsigned char *data; String *ps; - struct __go_empty_interface e; + Eface e; + const struct __go_type_descriptor *td; runtime_exitsyscall (0); len = __builtin_strlen (p); @@ -179,8 +179,9 @@ _cgo_panic (const char *p) ps = alloc_saved (sizeof *ps); ps->str = data; ps->len = len; - e.__type_descriptor = &string_type_descriptor; - e.__object = ps; + td = &string_type_descriptor; + memcpy(&e._type, &td, sizeof td); /* This is a const_cast. */ + e.data = ps; /* We don't call runtime_entersyscall here, because normally what will happen is that we will walk up the stack to a Go deferred Index: libgo/runtime/go-check-interface.c =================================================================== --- libgo/runtime/go-check-interface.c (revision 241341) +++ libgo/runtime/go-check-interface.c (working copy) @@ -1,46 +0,0 @@ -/* go-check-interface.c -- check an interface type for a conversion - - Copyright 2010 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. */ - -#include "runtime.h" -#include "go-panic.h" -#include "go-type.h" -#include "interface.h" - -/* Check that an interface type matches for a conversion to a - non-interface type. This panics if the types are bad. The actual - extraction of the object is inlined. */ - -void -__go_check_interface_type ( - const struct __go_type_descriptor *lhs_descriptor, - const struct __go_type_descriptor *rhs_descriptor, - const struct __go_type_descriptor *rhs_inter_descriptor) -{ - if (rhs_descriptor == NULL) - { - struct __go_empty_interface panic_arg; - - runtime_newTypeAssertionError(NULL, NULL, lhs_descriptor->__reflection, - NULL, &panic_arg); - __go_panic(panic_arg); - } - - if (lhs_descriptor != rhs_descriptor - && !__go_type_descriptors_equal (lhs_descriptor, rhs_descriptor) - && ((lhs_descriptor->__code & GO_CODE_MASK) != GO_UNSAFE_POINTER - || !__go_is_pointer_type (rhs_descriptor)) - && ((rhs_descriptor->__code & GO_CODE_MASK) != GO_UNSAFE_POINTER - || !__go_is_pointer_type (lhs_descriptor))) - { - struct __go_empty_interface panic_arg; - - runtime_newTypeAssertionError(rhs_inter_descriptor->__reflection, - rhs_descriptor->__reflection, - lhs_descriptor->__reflection, - NULL, &panic_arg); - __go_panic(panic_arg); - } -} Index: libgo/runtime/go-convert-interface.c =================================================================== --- libgo/runtime/go-convert-interface.c (revision 241341) +++ libgo/runtime/go-convert-interface.c (working copy) @@ -1,132 +0,0 @@ -/* go-convert-interface.c -- convert interfaces for Go. - - Copyright 2009 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. */ - -#include "runtime.h" -#include "go-alloc.h" -#include "go-assert.h" -#include "go-panic.h" -#include "go-string.h" -#include "go-type.h" -#include "interface.h" - -/* This is called when converting one interface type into another - interface type. LHS_DESCRIPTOR is the type descriptor of the - resulting interface. RHS_DESCRIPTOR is the type descriptor of the - object being converted. This builds and returns a new interface - method table. If any method in the LHS_DESCRIPTOR interface is not - implemented by the object, the conversion fails. If the conversion - fails, then if MAY_FAIL is true this returns NULL; otherwise, it - panics. */ - -void * -__go_convert_interface_2 (const struct __go_type_descriptor *lhs_descriptor, - const struct __go_type_descriptor *rhs_descriptor, - _Bool may_fail) -{ - const struct __go_interface_type *lhs_interface; - int lhs_method_count; - const struct __go_interface_method* lhs_methods; - const void **methods; - const struct __go_uncommon_type *rhs_uncommon; - int rhs_method_count; - const struct __go_method *p_rhs_method; - int i; - - if (rhs_descriptor == NULL) - { - /* A nil value always converts to nil. */ - return NULL; - } - - __go_assert ((lhs_descriptor->__code & GO_CODE_MASK) == GO_INTERFACE); - lhs_interface = (const struct __go_interface_type *) lhs_descriptor; - lhs_method_count = lhs_interface->__methods.__count; - lhs_methods = ((const struct __go_interface_method *) - lhs_interface->__methods.__values); - - /* This should not be called for an empty interface. */ - __go_assert (lhs_method_count > 0); - - rhs_uncommon = rhs_descriptor->__uncommon; - if (rhs_uncommon == NULL || rhs_uncommon->__methods.__count == 0) - { - struct __go_empty_interface panic_arg; - - if (may_fail) - return NULL; - - runtime_newTypeAssertionError (NULL, rhs_descriptor->__reflection, - lhs_descriptor->__reflection, - lhs_methods[0].__name, - &panic_arg); - __go_panic (panic_arg); - } - - rhs_method_count = rhs_uncommon->__methods.__count; - p_rhs_method = ((const struct __go_method *) - rhs_uncommon->__methods.__values); - - methods = NULL; - - for (i = 0; i < lhs_method_count; ++i) - { - const struct __go_interface_method *p_lhs_method; - - p_lhs_method = &lhs_methods[i]; - - while (rhs_method_count > 0 - && (!__go_ptr_strings_equal (p_lhs_method->__name, - p_rhs_method->__name) - || !__go_ptr_strings_equal (p_lhs_method->__pkg_path, - p_rhs_method->__pkg_path))) - { - ++p_rhs_method; - --rhs_method_count; - } - - if (rhs_method_count == 0 - || !__go_type_descriptors_equal (p_lhs_method->__type, - p_rhs_method->__mtype)) - { - struct __go_empty_interface panic_arg; - - if (methods != NULL) - __go_free (methods); - - if (may_fail) - return NULL; - - runtime_newTypeAssertionError (NULL, rhs_descriptor->__reflection, - lhs_descriptor->__reflection, - p_lhs_method->__name, &panic_arg); - __go_panic (panic_arg); - } - - if (methods == NULL) - { - methods = (const void **) __go_alloc ((lhs_method_count + 1) - * sizeof (void *)); - - /* The first field in the method table is always the type of - the object. */ - methods[0] = rhs_descriptor; - } - - methods[i + 1] = p_rhs_method->__function; - } - - return methods; -} - -/* This is called by the compiler to convert a value from one - interface type to another. */ - -void * -__go_convert_interface (const struct __go_type_descriptor *lhs_descriptor, - const struct __go_type_descriptor *rhs_descriptor) -{ - return __go_convert_interface_2 (lhs_descriptor, rhs_descriptor, 0); -} Index: libgo/runtime/go-deferred-recover.c =================================================================== --- libgo/runtime/go-deferred-recover.c (revision 241341) +++ libgo/runtime/go-deferred-recover.c (working copy) @@ -75,7 +75,7 @@ because you are not permitted to take the address of a predeclared function like recover. */ -struct __go_empty_interface +Eface __go_deferred_recover () { G *g; @@ -83,10 +83,10 @@ __go_deferred_recover () g = runtime_g (); if (g->_defer == NULL || g->_defer->_panic != g->_panic) { - struct __go_empty_interface ret; + Eface ret; - ret.__type_descriptor = NULL; - ret.__object = NULL; + ret._type = NULL; + ret.data = NULL; return ret; } return __go_recover (); Index: libgo/runtime/go-eface-compare.c =================================================================== --- libgo/runtime/go-eface-compare.c (revision 241341) +++ libgo/runtime/go-eface-compare.c (working copy) @@ -1,37 +0,0 @@ -/* go-eface-compare.c -- compare two empty values. - - Copyright 2010 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. */ - -#include "runtime.h" -#include "go-type.h" -#include "interface.h" - -/* Compare two interface values. Return 0 for equal, not zero for not - equal (return value is like strcmp). */ - -intgo -__go_empty_interface_compare (struct __go_empty_interface left, - struct __go_empty_interface right) -{ - const struct __go_type_descriptor *left_descriptor; - - left_descriptor = left.__type_descriptor; - - if (left_descriptor == NULL && right.__type_descriptor == NULL) - return 0; - if (left_descriptor == NULL || right.__type_descriptor == NULL) - return 1; - if (!__go_type_descriptors_equal (left_descriptor, - right.__type_descriptor)) - return 1; - if (left_descriptor->__equalfn == NULL) - runtime_panicstring ("comparing uncomparable types"); - if (__go_is_pointer_type (left_descriptor)) - return left.__object == right.__object ? 0 : 1; - if (!__go_call_equalfn (left_descriptor->__equalfn, left.__object, - right.__object, left_descriptor->__size)) - return 1; - return 0; -} Index: libgo/runtime/go-eface-val-compare.c =================================================================== --- libgo/runtime/go-eface-val-compare.c (revision 241341) +++ libgo/runtime/go-eface-val-compare.c (working copy) @@ -1,35 +0,0 @@ -/* go-eface-val-compare.c -- compare an empty interface with a value. - - Copyright 2010 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. */ - -#include "runtime.h" -#include "go-type.h" -#include "interface.h" - -/* Compare an empty interface with a value. Return 0 for equal, not - zero for not equal (return value is like strcmp). */ - -intgo -__go_empty_interface_value_compare ( - struct __go_empty_interface left, - const struct __go_type_descriptor *right_descriptor, - const void *val) -{ - const struct __go_type_descriptor *left_descriptor; - - left_descriptor = left.__type_descriptor; - if (left_descriptor == NULL) - return 1; - if (!__go_type_descriptors_equal (left_descriptor, right_descriptor)) - return 1; - if (left_descriptor->__equalfn == NULL) - runtime_panicstring ("comparing uncomparable types"); - if (__go_is_pointer_type (left_descriptor)) - return left.__object == val ? 0 : 1; - if (!__go_call_equalfn (left_descriptor->__equalfn, left.__object, val, - left_descriptor->__size)) - return 1; - return 0; -} Index: libgo/runtime/go-iface.goc =================================================================== --- libgo/runtime/go-iface.goc (revision 241341) +++ libgo/runtime/go-iface.goc (working copy) @@ -1,130 +0,0 @@ -// Copyright 2010 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 runtime -#include "runtime.h" -#include "go-type.h" -#include "interface.h" - -typedef struct __go_type_descriptor descriptor; -typedef const struct __go_type_descriptor const_descriptor; -typedef struct __go_interface interface; -typedef struct __go_empty_interface empty_interface; - -// Compare two type descriptors. -func ifacetypeeq(a *descriptor, b *descriptor) (eq bool) { - eq = __go_type_descriptors_equal(a, b); -} - -// Return the descriptor for an empty interface type.n -func efacetype(e empty_interface) (d *const_descriptor) { - return e.__type_descriptor; -} - -// Return the descriptor for a non-empty interface type. -func ifacetype(i interface) (d *const_descriptor) { - if (i.__methods == nil) { - return nil; - } - d = i.__methods[0]; -} - -// Convert an empty interface to an empty interface. -func ifaceE2E2(e empty_interface) (ret empty_interface, ok bool) { - ret = e; - ok = ret.__type_descriptor != nil; -} - -// Convert a non-empty interface to an empty interface. -func ifaceI2E2(i interface) (ret empty_interface, ok bool) { - if (i.__methods == nil) { - ret.__type_descriptor = nil; - ret.__object = nil; - ok = 0; - } else { - ret.__type_descriptor = i.__methods[0]; - ret.__object = i.__object; - ok = 1; - } -} - -// Convert an empty interface to a non-empty interface. -func ifaceE2I2(inter *descriptor, e empty_interface) (ret interface, ok bool) { - if (e.__type_descriptor == nil) { - ret.__methods = nil; - ret.__object = nil; - ok = 0; - } else { - ret.__methods = __go_convert_interface_2(inter, - e.__type_descriptor, - 1); - ret.__object = e.__object; - ok = ret.__methods != nil; - } -} - -// Convert a non-empty interface to a non-empty interface. -func ifaceI2I2(inter *descriptor, i interface) (ret interface, ok bool) { - if (i.__methods == nil) { - ret.__methods = nil; - ret.__object = nil; - ok = 0; - } else { - ret.__methods = __go_convert_interface_2(inter, - i.__methods[0], 1); - ret.__object = i.__object; - ok = ret.__methods != nil; - } -} - -// Convert an empty interface to a pointer type. -func ifaceE2T2P(inter *descriptor, e empty_interface) (ret *void, ok bool) { - if (!__go_type_descriptors_equal(inter, e.__type_descriptor)) { - ret = nil; - ok = 0; - } else { - ret = e.__object; - ok = 1; - } -} - -// Convert a non-empty interface to a pointer type. -func ifaceI2T2P(inter *descriptor, i interface) (ret *void, ok bool) { - if (i.__methods == nil - || !__go_type_descriptors_equal(inter, i.__methods[0])) { - ret = nil; - ok = 0; - } else { - ret = i.__object; - ok = 1; - } -} - -// Convert an empty interface to a non-pointer type. -func ifaceE2T2(inter *descriptor, e empty_interface, ret *void) (ok bool) { - if (!__go_type_descriptors_equal(inter, e.__type_descriptor)) { - __builtin_memset(ret, 0, inter->__size); - ok = 0; - } else { - __builtin_memcpy(ret, e.__object, inter->__size); - ok = 1; - } -} - -// Convert a non-empty interface to a non-pointer type. -func ifaceI2T2(inter *descriptor, i interface, ret *void) (ok bool) { - if (i.__methods == nil - || !__go_type_descriptors_equal(inter, i.__methods[0])) { - __builtin_memset(ret, 0, inter->__size); - ok = 0; - } else { - __builtin_memcpy(ret, i.__object, inter->__size); - ok = 1; - } -} - -// Return whether we can convert an interface to a type. -func ifaceI2Tp(to *descriptor, from *descriptor) (ok bool) { - ok = __go_can_convert_to_interface(to, from); -} Index: libgo/runtime/go-interface-compare.c =================================================================== --- libgo/runtime/go-interface-compare.c (revision 241341) +++ libgo/runtime/go-interface-compare.c (working copy) @@ -1,37 +0,0 @@ -/* go-interface-compare.c -- compare two interface values. - - Copyright 2009 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. */ - -#include - -#include "runtime.h" -#include "go-type.h" -#include "interface.h" - -/* Compare two interface values. Return 0 for equal, not zero for not - equal (return value is like strcmp). */ - -int -__go_interface_compare (struct __go_interface left, - struct __go_interface right) -{ - const struct __go_type_descriptor *left_descriptor; - - if (left.__methods == NULL && right.__methods == NULL) - return 0; - if (left.__methods == NULL || right.__methods == NULL) - return 1; - left_descriptor = left.__methods[0]; - if (!__go_type_descriptors_equal (left_descriptor, right.__methods[0])) - return 1; - if (left_descriptor->__equalfn == NULL) - runtime_panicstring ("comparing uncomparable types"); - if (__go_is_pointer_type (left_descriptor)) - return left.__object == right.__object ? 0 : 1; - if (!__go_call_equalfn (left_descriptor->__equalfn, left.__object, - right.__object, left_descriptor->__size)) - return 1; - return 0; -} Index: libgo/runtime/go-interface-eface-compare.c =================================================================== --- libgo/runtime/go-interface-eface-compare.c (revision 241341) +++ libgo/runtime/go-interface-eface-compare.c (working copy) @@ -1,36 +0,0 @@ -/* go-interface-eface-compare.c -- compare non-empty and empty interface. - - Copyright 2011 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. */ - -#include "runtime.h" -#include "go-type.h" -#include "interface.h" - -/* Compare a non-empty interface value with an empty interface value. - Return 0 for equal, not zero for not equal (return value is like - strcmp). */ - -intgo -__go_interface_empty_compare (struct __go_interface left, - struct __go_empty_interface right) -{ - const struct __go_type_descriptor *left_descriptor; - - if (left.__methods == NULL && right.__type_descriptor == NULL) - return 0; - if (left.__methods == NULL || right.__type_descriptor == NULL) - return 1; - left_descriptor = left.__methods[0]; - if (!__go_type_descriptors_equal (left_descriptor, right.__type_descriptor)) - return 1; - if (left_descriptor->__equalfn == NULL) - runtime_panicstring ("comparing uncomparable types"); - if (__go_is_pointer_type (left_descriptor)) - return left.__object == right.__object ? 0 : 1; - if (!__go_call_equalfn (left_descriptor->__equalfn, left.__object, - right.__object, left_descriptor->__size)) - return 1; - return 0; -} Index: libgo/runtime/go-interface-val-compare.c =================================================================== --- libgo/runtime/go-interface-val-compare.c (revision 241341) +++ libgo/runtime/go-interface-val-compare.c (working copy) @@ -1,35 +0,0 @@ -/* go-interface-val-compare.c -- compare an interface to a value. - - Copyright 2009 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. */ - -#include "runtime.h" -#include "go-type.h" -#include "interface.h" - -/* Compare two interface values. Return 0 for equal, not zero for not - equal (return value is like strcmp). */ - -intgo -__go_interface_value_compare ( - struct __go_interface left, - const struct __go_type_descriptor *right_descriptor, - const void *val) -{ - const struct __go_type_descriptor *left_descriptor; - - if (left.__methods == NULL) - return 1; - left_descriptor = left.__methods[0]; - if (!__go_type_descriptors_equal (left_descriptor, right_descriptor)) - return 1; - if (left_descriptor->__equalfn == NULL) - runtime_panicstring ("comparing uncomparable types"); - if (__go_is_pointer_type (left_descriptor)) - return left.__object == val ? 0 : 1; - if (!__go_call_equalfn (left_descriptor->__equalfn, left.__object, val, - left_descriptor->__size)) - return 1; - return 0; -} Index: libgo/runtime/go-panic.c =================================================================== --- libgo/runtime/go-panic.c (revision 241341) +++ libgo/runtime/go-panic.c (working copy) @@ -12,7 +12,6 @@ #include "malloc.h" #include "go-alloc.h" #include "go-panic.h" -#include "interface.h" /* Print the panic stack. This is used when there is no recover. */ @@ -35,7 +34,7 @@ __printpanics (Panic *p) function. */ void -__go_panic (struct __go_empty_interface arg) +__go_panic (Eface arg) { G *g; Panic *n; Index: libgo/runtime/go-panic.h =================================================================== --- libgo/runtime/go-panic.h (revision 241341) +++ libgo/runtime/go-panic.h (working copy) @@ -7,24 +7,18 @@ #ifndef LIBGO_GO_PANIC_H #define LIBGO_GO_PANIC_H -#include "interface.h" - -struct String; -struct __go_type_descriptor; - -extern void __go_panic (struct __go_empty_interface) +extern void __go_panic (Eface) __attribute__ ((noreturn)); -extern void __go_print_string (struct String); +extern void __go_print_string (String); -extern struct __go_empty_interface __go_recover (void); +extern Eface __go_recover (void); extern _Bool __go_can_recover (void *); extern void __go_makefunc_can_recover (void *retaddr); -struct location; -extern void __go_makefunc_ffi_can_recover (struct location *, int); +extern void __go_makefunc_ffi_can_recover (Location*, int); extern void __go_makefunc_returning (void); Index: libgo/runtime/go-recover.c =================================================================== --- libgo/runtime/go-recover.c (revision 241341) +++ libgo/runtime/go-recover.c (working copy) @@ -5,7 +5,6 @@ license that can be found in the LICENSE file. */ #include "runtime.h" -#include "interface.h" #include "go-panic.h" /* If the top of the defer stack can be recovered, then return it. @@ -200,7 +199,7 @@ __go_makefunc_can_recover (void *retaddr make the same decision. */ void -__go_makefunc_ffi_can_recover (struct location *loc, int n) +__go_makefunc_ffi_can_recover (Location *loc, int n) { Defer *d; const byte *name; @@ -252,7 +251,7 @@ __go_makefunc_returning (void) /* This is only called when it is valid for the caller to recover the value on top of the panic stack, if there is one. */ -struct __go_empty_interface +Eface __go_recover () { G *g; @@ -262,10 +261,10 @@ __go_recover () if (g->_panic == NULL || g->_panic->recovered) { - struct __go_empty_interface ret; + Eface ret; - ret.__type_descriptor = NULL; - ret.__object = NULL; + ret._type = NULL; + ret.data = NULL; return ret; } p = g->_panic; Index: libgo/runtime/go-strcmp.c =================================================================== --- libgo/runtime/go-strcmp.c (revision 241341) +++ libgo/runtime/go-strcmp.c (working copy) @@ -1,25 +0,0 @@ -/* go-strcmp.c -- the go string comparison function. - - Copyright 2009 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. */ - -#include "runtime.h" - -intgo -__go_strcmp(String s1, String s2) -{ - int i; - - i = __builtin_memcmp(s1.str, s2.str, - (s1.len < s2.len ? s1.len : s2.len)); - if (i != 0) - return i; - - if (s1.len < s2.len) - return -1; - else if (s1.len > s2.len) - return 1; - else - return 0; -} Index: libgo/runtime/go-strslice.c =================================================================== --- libgo/runtime/go-strslice.c (revision 241341) +++ libgo/runtime/go-strslice.c (working copy) @@ -4,8 +4,8 @@ Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. */ -#include "go-panic.h" #include "runtime.h" +#include "go-panic.h" #include "arch.h" #include "malloc.h" Index: libgo/runtime/go-type-eface.c =================================================================== --- libgo/runtime/go-type-eface.c (revision 241341) +++ libgo/runtime/go-type-eface.c (working copy) @@ -1,66 +0,0 @@ -/* go-type-eface.c -- hash and equality empty interface functions. - - Copyright 2010 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. */ - -#include "runtime.h" -#include "interface.h" -#include "go-type.h" - -/* A hash function for an empty interface. */ - -uintptr_t -__go_type_hash_empty_interface (const void *vval, uintptr_t seed, - uintptr_t key_size __attribute__ ((unused))) -{ - const struct __go_empty_interface *val; - const struct __go_type_descriptor *descriptor; - uintptr_t size; - - val = (const struct __go_empty_interface *) vval; - descriptor = val->__type_descriptor; - if (descriptor == NULL) - return 0; - if (descriptor->__hashfn == NULL) - runtime_panicstring ("hash of unhashable type"); - size = descriptor->__size; - if (__go_is_pointer_type (descriptor)) - return __go_call_hashfn (descriptor->__hashfn, &val->__object, seed, size); - else - return __go_call_hashfn (descriptor->__hashfn, val->__object, seed, size); -} - -const FuncVal __go_type_hash_empty_interface_descriptor = - { (void *) __go_type_hash_empty_interface }; - -/* An equality function for an empty interface. */ - -_Bool -__go_type_equal_empty_interface (const void *vv1, const void *vv2, - uintptr_t key_size __attribute__ ((unused))) -{ - const struct __go_empty_interface *v1; - const struct __go_empty_interface *v2; - const struct __go_type_descriptor* v1_descriptor; - const struct __go_type_descriptor* v2_descriptor; - - v1 = (const struct __go_empty_interface *) vv1; - v2 = (const struct __go_empty_interface *) vv2; - v1_descriptor = v1->__type_descriptor; - v2_descriptor = v2->__type_descriptor; - if (v1_descriptor == NULL || v2_descriptor == NULL) - return v1_descriptor == v2_descriptor; - if (!__go_type_descriptors_equal (v1_descriptor, v2_descriptor)) - return 0; - if (v1_descriptor->__equalfn == NULL) - runtime_panicstring ("comparing uncomparable types"); - if (__go_is_pointer_type (v1_descriptor)) - return v1->__object == v2->__object; - else - return __go_call_equalfn (v1_descriptor->__equalfn, v1->__object, - v2->__object, v1_descriptor->__size); -} - -const FuncVal __go_type_equal_empty_interface_descriptor = - { (void *) __go_type_equal_empty_interface }; Index: libgo/runtime/go-type-interface.c =================================================================== --- libgo/runtime/go-type-interface.c (revision 241341) +++ libgo/runtime/go-type-interface.c (working copy) @@ -1,66 +0,0 @@ -/* go-type-interface.c -- hash and equality interface functions. - - Copyright 2009 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. */ - -#include "runtime.h" -#include "interface.h" -#include "go-type.h" - -/* A hash function for an interface. */ - -uintptr_t -__go_type_hash_interface (const void *vval, uintptr_t seed, - uintptr_t key_size __attribute__ ((unused))) -{ - const struct __go_interface *val; - const struct __go_type_descriptor *descriptor; - uintptr_t size; - - val = (const struct __go_interface *) vval; - if (val->__methods == NULL) - return 0; - descriptor = (const struct __go_type_descriptor *) val->__methods[0]; - if (descriptor->__hashfn == NULL) - runtime_panicstring ("hash of unhashable type"); - size = descriptor->__size; - if (__go_is_pointer_type (descriptor)) - return __go_call_hashfn (descriptor->__hashfn, &val->__object, seed, size); - else - return __go_call_hashfn (descriptor->__hashfn, val->__object, seed, size); -} - -const FuncVal __go_type_hash_interface_descriptor = - { (void *) __go_type_hash_interface }; - -/* An equality function for an interface. */ - -_Bool -__go_type_equal_interface (const void *vv1, const void *vv2, - uintptr_t key_size __attribute__ ((unused))) -{ - const struct __go_interface *v1; - const struct __go_interface *v2; - const struct __go_type_descriptor* v1_descriptor; - const struct __go_type_descriptor* v2_descriptor; - - v1 = (const struct __go_interface *) vv1; - v2 = (const struct __go_interface *) vv2; - if (v1->__methods == NULL || v2->__methods == NULL) - return v1->__methods == v2->__methods; - v1_descriptor = (const struct __go_type_descriptor *) v1->__methods[0]; - v2_descriptor = (const struct __go_type_descriptor *) v2->__methods[0]; - if (!__go_type_descriptors_equal (v1_descriptor, v2_descriptor)) - return 0; - if (v1_descriptor->__equalfn == NULL) - runtime_panicstring ("comparing uncomparable types"); - if (__go_is_pointer_type (v1_descriptor)) - return v1->__object == v2->__object; - else - return __go_call_equalfn (v1_descriptor->__equalfn, v1->__object, - v2->__object, v1_descriptor->__size); -} - -const FuncVal __go_type_equal_interface_descriptor = - { (void *) __go_type_equal_interface }; Index: libgo/runtime/go-unsafe-new.c =================================================================== --- libgo/runtime/go-unsafe-new.c (revision 241341) +++ libgo/runtime/go-unsafe-new.c (working copy) @@ -8,7 +8,6 @@ #include "arch.h" #include "malloc.h" #include "go-type.h" -#include "interface.h" /* Implement unsafe_New, called from the reflect package. */ Index: libgo/runtime/go-unsafe-newarray.c =================================================================== --- libgo/runtime/go-unsafe-newarray.c (revision 241341) +++ libgo/runtime/go-unsafe-newarray.c (working copy) @@ -8,7 +8,6 @@ #include "arch.h" #include "malloc.h" #include "go-type.h" -#include "interface.h" /* Implement unsafe_NewArray, called from the reflect package. */ Index: libgo/runtime/go-unwind.c =================================================================== --- libgo/runtime/go-unwind.c (revision 241341) +++ libgo/runtime/go-unwind.c (working copy) @@ -67,8 +67,8 @@ __go_check_defer (_Bool *frame) n = (Panic *) __go_alloc (sizeof (Panic)); - n->arg.__type_descriptor = NULL; - n->arg.__object = NULL; + n->arg._type = NULL; + n->arg.data = NULL; n->recovered = 0; n->isforeign = 1; n->next = g->_panic; Index: libgo/runtime/heapdump.c =================================================================== --- libgo/runtime/heapdump.c (revision 241341) +++ libgo/runtime/heapdump.c (working copy) @@ -298,8 +298,8 @@ dumpgoroutine(G *gp) dumpint(TagPanic); dumpint((uintptr)p); dumpint((uintptr)gp); - dumpint((uintptr)p->arg.__type_descriptor); - dumpint((uintptr)p->arg.__object); + dumpint((uintptr)p->arg._type); + dumpint((uintptr)p->arg.data); dumpint((uintptr)0); dumpint((uintptr)p->next); } Index: libgo/runtime/interface.h =================================================================== --- libgo/runtime/interface.h (revision 241341) +++ libgo/runtime/interface.h (working copy) @@ -1,57 +0,0 @@ -/* interface.h -- the interface type for Go. - - Copyright 2009 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. */ - -#ifndef LIBGO_INTERFACE_H -#define LIBGO_INTERFACE_H - -struct __go_type_descriptor; - -/* A variable of interface type is an instance of this struct, if the - interface has any methods. */ - -struct __go_interface -{ - /* A pointer to the interface method table. The first pointer is - the type descriptor of the object. Subsequent pointers are - pointers to functions. This is effectively the vtable for this - interface. The function pointers are in the same order as the - list in the internal representation of the interface, which sorts - them by name. */ - const void **__methods; - - /* The object. If the object is a pointer--if the type descriptor - code is GO_PTR or GO_UNSAFE_POINTER--then this field is the value - of the object itself. Otherwise this is a pointer to memory - which holds the value. */ - void *__object; -}; - -/* A variable of an empty interface type is an instance of this - struct. */ - -struct __go_empty_interface -{ - /* The type descriptor of the object. */ - const struct __go_type_descriptor *__type_descriptor; - - /* The object. This is the same as __go_interface above. */ - void *__object; -}; - -extern void * -__go_convert_interface (const struct __go_type_descriptor *, - const struct __go_type_descriptor *); - -extern void * -__go_convert_interface_2 (const struct __go_type_descriptor *, - const struct __go_type_descriptor *, - _Bool may_fail); - -extern _Bool -__go_can_convert_to_interface(const struct __go_type_descriptor *, - const struct __go_type_descriptor *); - -#endif /* !defined(LIBGO_INTERFACE_H) */ Index: libgo/runtime/malloc.goc =================================================================== --- libgo/runtime/malloc.goc (revision 241341) +++ libgo/runtime/malloc.goc (working copy) @@ -14,12 +14,9 @@ package runtime #include "runtime.h" #include "arch.h" #include "malloc.h" -#include "interface.h" #include "go-type.h" // Map gccgo field names to gc field names. -// Eface aka __go_empty_interface. -#define type __type_descriptor // Type aka __go_type_descriptor #define kind __code #define string __reflection @@ -917,15 +914,15 @@ func SetFinalizer(obj Eface, finalizer E const Type *fint; const PtrType *ot; - if(obj.__type_descriptor == nil) { + if((Type*)obj._type == nil) { runtime_printf("runtime.SetFinalizer: first argument is nil interface\n"); goto throw; } - if((obj.__type_descriptor->kind&kindMask) != GO_PTR) { - runtime_printf("runtime.SetFinalizer: first argument is %S, not pointer\n", *obj.__type_descriptor->__reflection); + if((((Type*)obj._type)->kind&kindMask) != GO_PTR) { + runtime_printf("runtime.SetFinalizer: first argument is %S, not pointer\n", *((Type*)obj._type)->__reflection); goto throw; } - ot = (const PtrType*)obj.type; + ot = (const PtrType*)obj._type; // As an implementation detail we do not run finalizers for zero-sized objects, // because we use &runtime_zerobase for all such allocations. if(ot->__element_type != nil && ot->__element_type->__size == 0) @@ -937,49 +934,49 @@ func SetFinalizer(obj Eface, finalizer E // runtime.SetFinalizer(Foo, nil) // } // See issue 7656. - if((byte*)obj.__object < runtime_mheap.arena_start || runtime_mheap.arena_used <= (byte*)obj.__object) + if((byte*)obj.data < runtime_mheap.arena_start || runtime_mheap.arena_used <= (byte*)obj.data) return; - if(!runtime_mlookup(obj.__object, &base, &size, nil) || obj.__object != base) { + if(!runtime_mlookup(obj.data, &base, &size, nil) || obj.data != base) { // As an implementation detail we allow to set finalizers for an inner byte // of an object if it could come from tiny alloc (see mallocgc for details). if(ot->__element_type == nil || (ot->__element_type->kind&kindNoPointers) == 0 || ot->__element_type->__size >= TinySize) { - runtime_printf("runtime.SetFinalizer: pointer not at beginning of allocated block (%p)\n", obj.__object); + runtime_printf("runtime.SetFinalizer: pointer not at beginning of allocated block (%p)\n", obj.data); goto throw; } } - if(finalizer.__type_descriptor != nil) { + if((Type*)finalizer._type != nil) { runtime_createfing(); - if((finalizer.__type_descriptor->kind&kindMask) != GO_FUNC) + if((((Type*)finalizer._type)->kind&kindMask) != GO_FUNC) goto badfunc; - ft = (const FuncType*)finalizer.__type_descriptor; + ft = (const FuncType*)finalizer._type; if(ft->__dotdotdot || ft->__in.__count != 1) goto badfunc; fint = *(Type**)ft->__in.__values; - if(__go_type_descriptors_equal(fint, obj.__type_descriptor)) { + if(__go_type_descriptors_equal(fint, (Type*)obj._type)) { // ok - same type - } else if((fint->kind&kindMask) == GO_PTR && (fint->__uncommon == nil || fint->__uncommon->__name == nil || obj.type->__uncommon == nil || obj.type->__uncommon->__name == nil) && __go_type_descriptors_equal(((const PtrType*)fint)->__element_type, ((const PtrType*)obj.type)->__element_type)) { + } else if((fint->kind&kindMask) == GO_PTR && (fint->__uncommon == nil || fint->__uncommon->__name == nil || ((Type*)obj._type)->__uncommon == nil || ((Type*)obj._type)->__uncommon->__name == nil) && __go_type_descriptors_equal(((const PtrType*)fint)->__element_type, ((const PtrType*)obj._type)->__element_type)) { // ok - not same type, but both pointers, // one or the other is unnamed, and same element type, so assignable. } else if((fint->kind&kindMask) == GO_INTERFACE && ((const InterfaceType*)fint)->__methods.__count == 0) { // ok - satisfies empty interface - } else if((fint->kind&kindMask) == GO_INTERFACE && __go_convert_interface_2(fint, obj.__type_descriptor, 1) != nil) { + } else if((fint->kind&kindMask) == GO_INTERFACE && getitab(fint, (Type*)obj._type, true) != nil) { // ok - satisfies non-empty interface } else goto badfunc; - ot = (const PtrType*)obj.__type_descriptor; - if(!runtime_addfinalizer(obj.__object, *(FuncVal**)finalizer.__object, ft, ot)) { + ot = (const PtrType*)obj._type; + if(!runtime_addfinalizer(obj.data, *(FuncVal**)finalizer.data, ft, ot)) { runtime_printf("runtime.SetFinalizer: finalizer already set\n"); goto throw; } } else { // NOTE: asking to remove a finalizer when there currently isn't one set is OK. - runtime_removefinalizer(obj.__object); + runtime_removefinalizer(obj.data); } return; badfunc: - runtime_printf("runtime.SetFinalizer: cannot pass %S to finalizer %S\n", *obj.__type_descriptor->__reflection, *finalizer.__type_descriptor->__reflection); + runtime_printf("runtime.SetFinalizer: cannot pass %S to finalizer %S\n", *((Type*)obj._type)->__reflection, *((Type*)finalizer._type)->__reflection); throw: runtime_throw("runtime.SetFinalizer"); } Index: libgo/runtime/mgc0.c =================================================================== --- libgo/runtime/mgc0.c (revision 241341) +++ libgo/runtime/mgc0.c (working copy) @@ -62,8 +62,6 @@ // Slice aka __go_open_array. #define array __values #define cap __capacity -// Iface aka __go_interface -#define tab __methods // Hmap aka __go_map typedef struct __go_map Hmap; // Type aka __go_type_descriptor @@ -907,12 +905,12 @@ scanblock(Workbuf *wbuf, bool keepworkin eface = (Eface*)(stack_top.b + pc[1]); pc += 2; if(Debug > 2) - runtime_printf("gc_eface @%p: %p %p\n", stack_top.b+pc[1], eface->__type_descriptor, eface->__object); - if(eface->__type_descriptor == nil) + runtime_printf("gc_eface @%p: %p %p\n", stack_top.b+pc[1], eface->_type, eface->data); + if(eface->_type == nil) continue; // eface->type - t = eface->__type_descriptor; + t = eface->_type; if((const byte*)t >= arena_start && (const byte*)t < arena_used) { union { const Type *tc; Type *tr; } u; u.tc = t; @@ -921,13 +919,13 @@ scanblock(Workbuf *wbuf, bool keepworkin flushptrbuf(&sbuf); } - // eface->__object - if((byte*)eface->__object >= arena_start && (byte*)eface->__object < arena_used) { + // eface->data + if((byte*)eface->data >= arena_start && (byte*)eface->data < arena_used) { if(__go_is_pointer_type(t)) { if((t->__code & kindNoPointers)) continue; - obj = eface->__object; + obj = eface->data; if((t->__code & kindMask) == kindPtr) { // Only use type information if it is a pointer-containing type. // This matches the GC programs written by cmd/gc/reflect.c's @@ -937,7 +935,7 @@ scanblock(Workbuf *wbuf, bool keepworkin objti = (uintptr)((const PtrType*)t)->elem->__gc; } } else { - obj = eface->__object; + obj = eface->data; objti = (uintptr)t->__gc; } } @@ -947,7 +945,7 @@ scanblock(Workbuf *wbuf, bool keepworkin iface = (Iface*)(stack_top.b + pc[1]); pc += 2; if(Debug > 2) - runtime_printf("gc_iface @%p: %p/%p %p\n", stack_top.b+pc[1], iface->__methods[0], nil, iface->__object); + runtime_printf("gc_iface @%p: %p/%p %p\n", stack_top.b+pc[1], *(Type**)iface->tab, nil, iface->data); if(iface->tab == nil) continue; @@ -959,13 +957,13 @@ scanblock(Workbuf *wbuf, bool keepworkin } // iface->data - if((byte*)iface->__object >= arena_start && (byte*)iface->__object < arena_used) { - t = (const Type*)iface->tab[0]; + if((byte*)iface->data >= arena_start && (byte*)iface->data < arena_used) { + t = *(Type**)iface->tab; if(__go_is_pointer_type(t)) { if((t->__code & kindNoPointers)) continue; - obj = iface->__object; + obj = iface->data; if((t->__code & kindMask) == kindPtr) { // Only use type information if it is a pointer-containing type. // This matches the GC programs written by cmd/gc/reflect.c's @@ -975,7 +973,7 @@ scanblock(Workbuf *wbuf, bool keepworkin objti = (uintptr)((const PtrType*)t)->elem->__gc; } } else { - obj = iface->__object; + obj = iface->data; objti = (uintptr)t->__gc; } } @@ -2448,8 +2446,8 @@ runfinq(void* dummy __attribute__ ((unus fb = nil; next = nil; i = 0; - ef.__type_descriptor = nil; - ef.__object = nil; + ef._type = nil; + ef.data = nil; // force flush to memory USED(&f); @@ -2483,16 +2481,18 @@ runfinq(void* dummy __attribute__ ((unus param = &f->arg; } else if(((const InterfaceType*)fint)->__methods.__count == 0) { // convert to empty interface - ef.__type_descriptor = (const Type*)f->ot; - ef.__object = f->arg; + // using memcpy as const_cast. + memcpy(&ef._type, &f->ot, + sizeof ef._type); + ef.data = f->arg; param = &ef; } else { // convert to interface with methods - iface.__methods = __go_convert_interface_2((const Type*)fint, - (const Type*)f->ot, - 1); - iface.__object = f->arg; - if(iface.__methods == nil) + iface.tab = getitab(fint, + (const Type*)f->ot, + true); + iface.data = f->arg; + if(iface.data == nil) runtime_throw("invalid type conversion in runfinq"); param = &iface; } @@ -2514,8 +2514,8 @@ runfinq(void* dummy __attribute__ ((unus fb = nil; next = nil; i = 0; - ef.__type_descriptor = nil; - ef.__object = nil; + ef._type = nil; + ef.data = nil; runtime_gc(1); // trigger another gc to clean up the finalized objects, if possible } } Index: libgo/runtime/reflect.goc =================================================================== --- libgo/runtime/reflect.goc (revision 241341) +++ libgo/runtime/reflect.goc (working copy) @@ -1,25 +0,0 @@ -// Copyright 2010 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 reflect -#include "runtime.h" -#include "go-type.h" -#include "interface.h" -#include "go-panic.h" - -func ifaceE2I(inter *Type, e Eface, ret *Iface) { - const Type *t; - Eface err; - - t = e.__type_descriptor; - if(t == nil) { - // explicit conversions require non-nil interface value. - runtime_newTypeAssertionError( - nil, nil, inter->__reflection, - nil, &err); - runtime_panic(err); - } - ret->__object = e.__object; - ret->__methods = __go_convert_interface(inter, t); -} Index: libgo/runtime/runtime.h =================================================================== --- libgo/runtime/runtime.h (revision 241341) +++ libgo/runtime/runtime.h (working copy) @@ -22,7 +22,6 @@ #include #endif -#include "interface.h" #include "go-alloc.h" #define _STRINGIFY2_(x) #x @@ -76,8 +75,8 @@ typedef struct PollDesc PollDesc; typedef struct sudog SudoG; typedef struct __go_open_array Slice; -typedef struct __go_interface Iface; -typedef struct __go_empty_interface Eface; +typedef struct iface Iface; +typedef struct eface Eface; typedef struct __go_type_descriptor Type; typedef struct _defer Defer; typedef struct _panic Panic; @@ -105,7 +104,6 @@ struct FuncVal }; #include "array.h" -#include "interface.h" // Rename Go types generated by mkrsysinfo.sh from C types, to avoid // the name conflict. @@ -587,3 +585,7 @@ extern _Bool runtime_iscgo; extern _Bool runtime_cgoHasExtraM; extern Hchan *runtime_main_init_done; extern uintptr __go_end __attribute__ ((weak)); +extern void *getitab(const struct __go_type_descriptor *, + const struct __go_type_descriptor *, + _Bool) + __asm__ (GOSYM_PREFIX "runtime.getitab"); Index: libgo/runtime/runtime1.goc =================================================================== --- libgo/runtime/runtime1.goc (revision 241341) +++ libgo/runtime/runtime1.goc (working copy) @@ -40,7 +40,7 @@ func parForIters(desc *ParFor, tid uintp } func typestring(e Eface) (s String) { - s = *e.__type_descriptor->__reflection; + s = *((Type*)e._type)->__reflection; } func golockedOSThread() (ret bool) {