2015-02-13 14:40:36 -05:00
// 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.
package gc
import (
"bytes"
"cmd/internal/obj"
2015-02-27 16:05:30 +09:00
"crypto/md5"
"encoding/binary"
2015-02-13 14:40:36 -05:00
"fmt"
"os"
"sort"
"strings"
"unicode"
"unicode/utf8"
)
type Error struct {
lineno int
seq int
msg string
}
var errors [ ] Error
func errorexit ( ) {
Flusherrors ( )
if outfile != "" {
os . Remove ( outfile )
}
os . Exit ( 2 )
}
func parserline ( ) int {
return int ( lineno )
}
func adderrorname ( n * Node ) {
if n . Op != ODOT {
return
}
2015-04-17 12:03:22 -04:00
old := fmt . Sprintf ( "%v: undefined: %v\n" , n . Line ( ) , n . Left )
2015-02-13 14:40:36 -05:00
if len ( errors ) > 0 && int32 ( errors [ len ( errors ) - 1 ] . lineno ) == n . Lineno && errors [ len ( errors ) - 1 ] . msg == old {
2015-04-17 12:03:22 -04:00
errors [ len ( errors ) - 1 ] . msg = fmt . Sprintf ( "%v: undefined: %v in %v\n" , n . Line ( ) , n . Left , n )
2015-02-13 14:40:36 -05:00
}
}
2015-04-02 17:01:14 -07:00
func adderr ( line int , format string , args ... interface { } ) {
2015-02-13 14:40:36 -05:00
errors = append ( errors , Error {
seq : len ( errors ) ,
lineno : line ,
msg : fmt . Sprintf ( "%v: %s\n" , Ctxt . Line ( line ) , fmt . Sprintf ( format , args ... ) ) ,
} )
}
2015-09-02 20:25:46 +02:00
// errcmp sorts errors by line, then seq, then message.
2015-02-13 14:40:36 -05:00
type errcmp [ ] Error
2015-09-02 20:25:46 +02:00
func ( x errcmp ) Len ( ) int { return len ( x ) }
func ( x errcmp ) Swap ( i , j int ) { x [ i ] , x [ j ] = x [ j ] , x [ i ] }
2015-02-13 14:40:36 -05:00
func ( x errcmp ) Less ( i , j int ) bool {
2015-02-23 16:07:24 -05:00
a := & x [ i ]
b := & x [ j ]
2015-02-13 14:40:36 -05:00
if a . lineno != b . lineno {
2015-09-02 20:25:46 +02:00
return a . lineno < b . lineno
2015-02-13 14:40:36 -05:00
}
if a . seq != b . seq {
2015-09-02 20:25:46 +02:00
return a . seq < b . seq
2015-02-13 14:40:36 -05:00
}
2015-09-02 20:25:46 +02:00
return a . msg < b . msg
2015-02-13 14:40:36 -05:00
}
func Flusherrors ( ) {
2015-05-01 11:51:47 +10:00
bstdout . Flush ( )
2015-02-13 14:40:36 -05:00
if len ( errors ) == 0 {
return
}
2015-09-02 20:25:46 +02:00
sort . Sort ( errcmp ( errors ) )
2015-02-23 16:07:24 -05:00
for i := 0 ; i < len ( errors ) ; i ++ {
2015-02-13 14:40:36 -05:00
if i == 0 || errors [ i ] . msg != errors [ i - 1 ] . msg {
fmt . Printf ( "%s" , errors [ i ] . msg )
}
}
errors = errors [ : 0 ]
}
func hcrash ( ) {
if Debug [ 'h' ] != 0 {
Flusherrors ( )
if outfile != "" {
os . Remove ( outfile )
}
var x * int
* x = 0
}
}
2015-04-02 17:01:14 -07:00
func yyerrorl ( line int , format string , args ... interface { } ) {
adderr ( line , format , args ... )
2015-02-13 14:40:36 -05:00
hcrash ( )
nerrors ++
2015-02-17 22:13:49 -05:00
if nsavederrors + nerrors >= 10 && Debug [ 'e' ] == 0 {
2015-02-13 14:40:36 -05:00
Flusherrors ( )
fmt . Printf ( "%v: too many errors\n" , Ctxt . Line ( line ) )
errorexit ( )
}
}
var yyerror_lastsyntax int
2015-04-02 17:01:14 -07:00
func Yyerror ( format string , args ... interface { } ) {
msg := fmt . Sprintf ( format , args ... )
if strings . HasPrefix ( msg , "syntax error" ) {
2015-02-13 14:40:36 -05:00
nsyntaxerrors ++
// only one syntax error per line
if int32 ( yyerror_lastsyntax ) == lexlineno {
return
}
yyerror_lastsyntax = int ( lexlineno )
// plain "syntax error" gets "near foo" added
2015-04-02 17:01:14 -07:00
if msg == "syntax error" {
2015-02-13 14:40:36 -05:00
yyerrorl ( int ( lexlineno ) , "syntax error near %s" , lexbuf . String ( ) )
return
}
2015-04-02 17:01:14 -07:00
yyerrorl ( int ( lexlineno ) , "%s" , msg )
2015-02-13 14:40:36 -05:00
return
}
2015-04-02 17:01:14 -07:00
adderr ( parserline ( ) , "%s" , msg )
2015-02-13 14:40:36 -05:00
hcrash ( )
nerrors ++
2015-02-17 22:13:49 -05:00
if nsavederrors + nerrors >= 10 && Debug [ 'e' ] == 0 {
2015-02-13 14:40:36 -05:00
Flusherrors ( )
fmt . Printf ( "%v: too many errors\n" , Ctxt . Line ( parserline ( ) ) )
errorexit ( )
}
}
func Warn ( fmt_ string , args ... interface { } ) {
2015-04-02 17:01:14 -07:00
adderr ( parserline ( ) , fmt_ , args ... )
2015-02-13 14:40:36 -05:00
hcrash ( )
}
func Warnl ( line int , fmt_ string , args ... interface { } ) {
2015-04-02 17:01:14 -07:00
adderr ( line , fmt_ , args ... )
2015-02-13 14:40:36 -05:00
if Debug [ 'm' ] != 0 {
Flusherrors ( )
}
}
2015-08-30 23:10:03 +02:00
func Fatalf ( fmt_ string , args ... interface { } ) {
2015-02-13 14:40:36 -05:00
Flusherrors ( )
fmt . Printf ( "%v: internal compiler error: " , Ctxt . Line ( int ( lineno ) ) )
fmt . Printf ( fmt_ , args ... )
fmt . Printf ( "\n" )
// If this is a released compiler version, ask for a bug report.
if strings . HasPrefix ( obj . Getgoversion ( ) , "release" ) {
fmt . Printf ( "\n" )
fmt . Printf ( "Please file a bug report including a short program that triggers the error.\n" )
fmt . Printf ( "https://golang.org/issue/new\n" )
}
hcrash ( )
errorexit ( )
}
2015-04-20 13:32:40 -07:00
func linehistpragma ( file string ) {
2015-02-13 14:40:36 -05:00
if Debug [ 'i' ] != 0 {
2015-04-20 13:32:40 -07:00
fmt . Printf ( "pragma %s at line %v\n" , file , Ctxt . Line ( int ( lexlineno ) ) )
}
Ctxt . AddImport ( file )
}
func linehistpush ( file string ) {
if Debug [ 'i' ] != 0 {
fmt . Printf ( "import %s at line %v\n" , file , Ctxt . Line ( int ( lexlineno ) ) )
2015-02-13 14:40:36 -05:00
}
2015-04-20 13:32:40 -07:00
Ctxt . LineHist . Push ( int ( lexlineno ) , file )
}
2015-02-13 14:40:36 -05:00
2015-04-20 13:32:40 -07:00
func linehistpop ( ) {
if Debug [ 'i' ] != 0 {
fmt . Printf ( "end of import at line %v\n" , Ctxt . Line ( int ( lexlineno ) ) )
}
Ctxt . LineHist . Pop ( int ( lexlineno ) )
}
func linehistupdate ( file string , off int ) {
if Debug [ 'i' ] != 0 {
fmt . Printf ( "line %s at line %v\n" , file , Ctxt . Line ( int ( lexlineno ) ) )
2015-02-13 14:40:36 -05:00
}
2015-04-20 13:32:40 -07:00
Ctxt . LineHist . Update ( int ( lexlineno ) , file , off )
2015-02-13 14:40:36 -05:00
}
func setlineno ( n * Node ) int32 {
2015-02-23 16:07:24 -05:00
lno := lineno
2015-02-13 14:40:36 -05:00
if n != nil {
switch n . Op {
2015-06-28 23:12:21 -04:00
case ONAME , OTYPE , OPACK :
2015-02-13 14:40:36 -05:00
break
2015-06-28 23:12:21 -04:00
case OLITERAL :
if n . Sym != nil {
break
}
fallthrough
2015-02-13 14:40:36 -05:00
default :
lineno = n . Lineno
if lineno == 0 {
if Debug [ 'K' ] != 0 {
Warn ( "setlineno: line 0" )
}
lineno = lno
}
}
}
return lno
}
2015-03-02 16:21:15 -05:00
func Lookup ( name string ) * Sym {
return localpkg . Lookup ( name )
}
2015-02-13 14:40:36 -05:00
2015-03-06 12:02:24 -08:00
func Lookupf ( format string , a ... interface { } ) * Sym {
return Lookup ( fmt . Sprintf ( format , a ... ) )
}
2015-03-02 16:21:15 -05:00
func LookupBytes ( name [ ] byte ) * Sym {
return localpkg . LookupBytes ( name )
}
2015-02-13 14:40:36 -05:00
2015-03-02 16:21:15 -05:00
var initSyms [ ] * Sym
2015-03-12 18:45:30 -04:00
var nopkg = & Pkg {
Syms : make ( map [ string ] * Sym ) ,
}
2015-03-02 16:21:15 -05:00
func ( pkg * Pkg ) Lookup ( name string ) * Sym {
if pkg == nil {
pkg = nopkg
}
if s := pkg . Syms [ name ] ; s != nil {
return s
2015-02-13 14:40:36 -05:00
}
2015-03-02 16:21:15 -05:00
s := & Sym {
Name : name ,
Pkg : pkg ,
Lexical : LNAME ,
}
2015-03-12 18:45:30 -04:00
if name == "init" {
2015-03-02 16:21:15 -05:00
initSyms = append ( initSyms , s )
}
pkg . Syms [ name ] = s
return s
2015-02-13 14:40:36 -05:00
}
2015-03-02 16:21:15 -05:00
func ( pkg * Pkg ) LookupBytes ( name [ ] byte ) * Sym {
if pkg == nil {
pkg = nopkg
}
if s := pkg . Syms [ string ( name ) ] ; s != nil {
return s
}
str := internString ( name )
return pkg . Lookup ( str )
2015-02-13 14:40:36 -05:00
}
func Pkglookup ( name string , pkg * Pkg ) * Sym {
2015-03-02 16:21:15 -05:00
return pkg . Lookup ( name )
2015-02-13 14:40:36 -05:00
}
func restrictlookup ( name string , pkg * Pkg ) * Sym {
if ! exportname ( name ) && pkg != localpkg {
Yyerror ( "cannot refer to unexported name %s.%s" , pkg . Name , name )
}
return Pkglookup ( name , pkg )
}
// find all the exported symbols in package opkg
// and make them available in the current package
func importdot ( opkg * Pkg , pack * Node ) {
var s1 * Sym
var pkgerror string
2015-02-23 16:07:24 -05:00
n := 0
2015-03-02 16:21:15 -05:00
for _ , s := range opkg . Syms {
if s . Def == nil {
continue
2015-02-13 14:40:36 -05:00
}
2015-03-02 16:21:15 -05:00
if ! exportname ( s . Name ) || strings . ContainsRune ( s . Name , 0xb7 ) { // 0xb7 = center dot
continue
}
s1 = Lookup ( s . Name )
if s1 . Def != nil {
pkgerror = fmt . Sprintf ( "during import %q" , opkg . Path )
redeclare ( s1 , pkgerror )
continue
}
s1 . Def = s . Def
s1 . Block = s . Block
2015-05-26 23:08:39 -04:00
if s1 . Def . Name == nil {
Dump ( "s1def" , s1 . Def )
2015-08-30 23:10:03 +02:00
Fatalf ( "missing Name" )
2015-05-26 23:08:39 -04:00
}
s1 . Def . Name . Pack = pack
2015-03-02 16:21:15 -05:00
s1 . Origpkg = opkg
n ++
2015-02-13 14:40:36 -05:00
}
if n == 0 {
// can't possibly be used - there were no symbols
2015-03-02 16:03:26 -05:00
yyerrorl ( int ( pack . Lineno ) , "imported and not used: %q" , opkg . Path )
2015-02-13 14:40:36 -05:00
}
}
2015-09-24 23:21:18 +02:00
func Nod ( op Op , nleft * Node , nright * Node ) * Node {
2015-02-23 16:07:24 -05:00
n := new ( Node )
2015-09-24 23:21:18 +02:00
n . Op = op
2015-02-13 14:40:36 -05:00
n . Left = nleft
n . Right = nright
n . Lineno = int32 ( parserline ( ) )
n . Xoffset = BADWIDTH
n . Orig = n
2015-03-10 21:37:13 -07:00
switch op {
case OCLOSURE , ODCLFUNC :
n . Func = new ( Func )
2015-05-27 07:31:56 -04:00
n . Func . FCurfn = Curfn
2015-04-03 17:43:38 -07:00
case ONAME :
n . Name = new ( Name )
2015-05-27 00:44:05 -04:00
n . Name . Param = new ( Param )
2015-05-26 23:18:27 -04:00
case OLABEL , OPACK :
2015-05-26 22:19:27 -04:00
n . Name = new ( Name )
2015-05-18 10:27:59 -07:00
case ODCLFIELD :
2015-05-27 00:44:05 -04:00
if nleft != nil {
n . Name = nleft . Name
} else {
n . Name = new ( Name )
n . Name . Param = new ( Param )
}
2015-03-10 21:37:13 -07:00
}
2015-05-27 07:31:56 -04:00
if n . Name != nil {
n . Name . Curfn = Curfn
}
2015-02-13 14:40:36 -05:00
return n
}
func saveorignode ( n * Node ) {
if n . Orig != nil {
return
}
2015-09-24 23:21:18 +02:00
norig := Nod ( n . Op , nil , nil )
2015-02-13 14:40:36 -05:00
* norig = * n
n . Orig = norig
}
// ispaddedfield reports whether the given field
// is followed by padding. For the case where t is
// the last field, total gives the size of the enclosing struct.
2015-02-17 22:13:49 -05:00
func ispaddedfield ( t * Type , total int64 ) bool {
2015-02-13 14:40:36 -05:00
if t . Etype != TFIELD {
2015-08-30 23:10:03 +02:00
Fatalf ( "ispaddedfield called non-field %v" , t )
2015-02-13 14:40:36 -05:00
}
if t . Down == nil {
2015-02-17 22:13:49 -05:00
return t . Width + t . Type . Width != total
2015-02-13 14:40:36 -05:00
}
2015-02-17 22:13:49 -05:00
return t . Width + t . Type . Width != t . Down . Width
2015-02-13 14:40:36 -05:00
}
func algtype1 ( t * Type , bad * * Type ) int {
if bad != nil {
* bad = nil
}
2015-09-07 10:37:26 +10:00
if t . Broke {
2015-02-13 14:40:36 -05:00
return AMEM
}
2015-09-08 03:51:30 +02:00
if t . Noalg {
2015-02-13 14:40:36 -05:00
return ANOEQ
}
switch t . Etype {
// will be defined later.
2015-04-01 09:38:44 -07:00
case TANY , TFORW :
2015-02-13 14:40:36 -05:00
* bad = t
return - 1
case TINT8 ,
TUINT8 ,
TINT16 ,
TUINT16 ,
TINT32 ,
TUINT32 ,
TINT64 ,
TUINT64 ,
TINT ,
TUINT ,
TUINTPTR ,
TBOOL ,
TPTR32 ,
TPTR64 ,
TCHAN ,
TUNSAFEPTR :
return AMEM
2015-04-01 09:38:44 -07:00
case TFUNC , TMAP :
2015-02-13 14:40:36 -05:00
if bad != nil {
* bad = t
}
return ANOEQ
case TFLOAT32 :
return AFLOAT32
case TFLOAT64 :
return AFLOAT64
case TCOMPLEX64 :
return ACPLX64
case TCOMPLEX128 :
return ACPLX128
case TSTRING :
return ASTRING
case TINTER :
2015-02-17 22:13:49 -05:00
if isnilinter ( t ) {
2015-02-13 14:40:36 -05:00
return ANILINTER
}
return AINTER
case TARRAY :
2015-02-17 22:13:49 -05:00
if Isslice ( t ) {
2015-02-13 14:40:36 -05:00
if bad != nil {
* bad = t
}
return ANOEQ
}
2015-02-23 16:07:24 -05:00
a := algtype1 ( t . Type , bad )
2015-02-13 14:40:36 -05:00
if a == ANOEQ || a == AMEM {
if a == ANOEQ && bad != nil {
* bad = t
}
return a
}
2015-05-04 15:02:09 -07:00
switch t . Bound {
case 0 :
// We checked above that the element type is comparable.
return AMEM
case 1 :
// Single-element array is same as its lone element.
return a
}
2015-02-13 14:40:36 -05:00
return - 1 // needs special compare
case TSTRUCT :
if t . Type != nil && t . Type . Down == nil && ! isblanksym ( t . Type . Sym ) {
// One-field struct is same as that one field alone.
return algtype1 ( t . Type . Type , bad )
}
2015-02-23 16:07:24 -05:00
ret := AMEM
var a int
for t1 := t . Type ; t1 != nil ; t1 = t1 . Down {
2015-02-13 14:40:36 -05:00
// All fields must be comparable.
a = algtype1 ( t1 . Type , bad )
if a == ANOEQ {
return ANOEQ
}
// Blank fields, padded fields, fields with non-memory
// equality need special compare.
2015-02-17 22:13:49 -05:00
if a != AMEM || isblanksym ( t1 . Sym ) || ispaddedfield ( t1 , t . Width ) {
2015-02-13 14:40:36 -05:00
ret = - 1
continue
}
}
return ret
}
2015-08-30 23:10:03 +02:00
Fatalf ( "algtype1: unexpected type %v" , t )
2015-02-13 14:40:36 -05:00
return 0
}
func algtype ( t * Type ) int {
2015-02-23 16:07:24 -05:00
a := algtype1 ( t , nil )
2016-02-20 22:52:15 -08:00
if a == AMEM {
2015-02-13 14:40:36 -05:00
switch t . Width {
case 0 :
2016-02-20 22:52:15 -08:00
return AMEM0
2015-02-13 14:40:36 -05:00
case 1 :
2016-02-20 22:52:15 -08:00
return AMEM8
2015-02-13 14:40:36 -05:00
case 2 :
2016-02-20 22:52:15 -08:00
return AMEM16
2015-02-13 14:40:36 -05:00
case 4 :
2016-02-20 22:52:15 -08:00
return AMEM32
2015-02-13 14:40:36 -05:00
case 8 :
2016-02-20 22:52:15 -08:00
return AMEM64
2015-02-13 14:40:36 -05:00
case 16 :
2016-02-20 22:52:15 -08:00
return AMEM128
2015-02-13 14:40:36 -05:00
}
}
return a
}
func maptype ( key * Type , val * Type ) * Type {
if key != nil {
2015-02-23 16:07:24 -05:00
var bad * Type
atype := algtype1 ( key , & bad )
2015-09-24 23:21:18 +02:00
var mtype EType
2015-02-13 14:40:36 -05:00
if bad == nil {
2015-09-24 23:21:18 +02:00
mtype = key . Etype
2015-02-13 14:40:36 -05:00
} else {
2015-09-24 23:21:18 +02:00
mtype = bad . Etype
2015-02-13 14:40:36 -05:00
}
switch mtype {
default :
if atype == ANOEQ {
2015-04-17 12:03:22 -04:00
Yyerror ( "invalid map key type %v" , key )
2015-02-13 14:40:36 -05:00
}
// will be resolved later.
case TANY :
break
// map[key] used during definition of key.
// postpone check until key is fully defined.
// if there are multiple uses of map[key]
// before key is fully defined, the error
// will only be printed for the first one.
// good enough.
case TFORW :
if key . Maplineno == 0 {
key . Maplineno = lineno
}
}
}
2015-02-23 16:07:24 -05:00
t := typ ( TMAP )
2015-02-13 14:40:36 -05:00
t . Down = key
t . Type = val
return t
}
2015-09-24 23:21:18 +02:00
func typ ( et EType ) * Type {
2015-02-23 16:07:24 -05:00
t := new ( Type )
2015-09-24 23:21:18 +02:00
t . Etype = et
2015-02-13 14:40:36 -05:00
t . Width = BADWIDTH
t . Lineno = int ( lineno )
t . Orig = t
return t
}
2015-09-14 20:53:44 +02:00
// methcmp sorts by symbol, then by package path for unexported symbols.
2015-02-13 14:40:36 -05:00
type methcmp [ ] * Type
2015-09-14 20:53:44 +02:00
func ( x methcmp ) Len ( ) int { return len ( x ) }
func ( x methcmp ) Swap ( i , j int ) { x [ i ] , x [ j ] = x [ j ] , x [ i ] }
2015-02-13 14:40:36 -05:00
func ( x methcmp ) Less ( i , j int ) bool {
2015-02-23 16:07:24 -05:00
a := x [ i ]
b := x [ j ]
2015-02-13 14:40:36 -05:00
if a . Sym == nil && b . Sym == nil {
return false
}
if a . Sym == nil {
return true
}
if b . Sym == nil {
2015-09-14 20:53:44 +02:00
return false
2015-02-13 14:40:36 -05:00
}
2015-09-14 20:53:44 +02:00
if a . Sym . Name != b . Sym . Name {
return a . Sym . Name < b . Sym . Name
2015-02-13 14:40:36 -05:00
}
if ! exportname ( a . Sym . Name ) {
2015-09-14 20:53:44 +02:00
if a . Sym . Pkg . Path != b . Sym . Pkg . Path {
return a . Sym . Pkg . Path < b . Sym . Pkg . Path
2015-02-13 14:40:36 -05:00
}
}
return false
}
func sortinter ( t * Type ) * Type {
if t . Type == nil || t . Type . Down == nil {
return t
}
2015-09-14 20:53:44 +02:00
var a [ ] * Type
2015-02-23 16:07:24 -05:00
for f := t . Type ; f != nil ; f = f . Down {
2015-09-14 20:53:44 +02:00
a = append ( a , f )
2015-02-13 14:40:36 -05:00
}
2015-09-14 20:53:44 +02:00
sort . Sort ( methcmp ( a ) )
n := len ( a ) // n > 0 due to initial conditions.
for i := 0 ; i < n - 1 ; i ++ {
a [ i ] . Down = a [ i + 1 ]
2015-02-13 14:40:36 -05:00
}
2015-09-14 20:53:44 +02:00
a [ n - 1 ] . Down = nil
2015-02-13 14:40:36 -05:00
2015-09-14 20:53:44 +02:00
t . Type = a [ 0 ]
2015-02-13 14:40:36 -05:00
return t
}
func Nodintconst ( v int64 ) * Node {
2015-02-23 16:07:24 -05:00
c := Nod ( OLITERAL , nil , nil )
2015-04-02 19:58:37 -07:00
c . Addable = true
2015-05-27 00:47:05 -04:00
c . SetVal ( Val { new ( Mpint ) } )
Mpmovecfix ( c . Val ( ) . U . ( * Mpint ) , v )
2015-02-13 14:40:36 -05:00
c . Type = Types [ TIDEAL ]
ullmancalc ( c )
return c
}
func nodfltconst ( v * Mpflt ) * Node {
2015-02-23 16:07:24 -05:00
c := Nod ( OLITERAL , nil , nil )
2015-04-02 19:58:37 -07:00
c . Addable = true
2015-05-27 00:47:05 -04:00
c . SetVal ( Val { newMpflt ( ) } )
mpmovefltflt ( c . Val ( ) . U . ( * Mpflt ) , v )
2015-02-13 14:40:36 -05:00
c . Type = Types [ TIDEAL ]
ullmancalc ( c )
return c
}
func Nodconst ( n * Node , t * Type , v int64 ) {
* n = Node { }
n . Op = OLITERAL
2015-04-02 19:58:37 -07:00
n . Addable = true
2015-02-13 14:40:36 -05:00
ullmancalc ( n )
2015-05-27 00:47:05 -04:00
n . SetVal ( Val { new ( Mpint ) } )
Mpmovecfix ( n . Val ( ) . U . ( * Mpint ) , v )
2015-02-13 14:40:36 -05:00
n . Type = t
2015-03-01 07:54:01 +00:00
if Isfloat [ t . Etype ] {
2015-08-30 23:10:03 +02:00
Fatalf ( "nodconst: bad type %v" , t )
2015-02-13 14:40:36 -05:00
}
}
func nodnil ( ) * Node {
2015-02-23 16:07:24 -05:00
c := Nodintconst ( 0 )
2015-05-27 00:47:05 -04:00
c . SetVal ( Val { new ( NilVal ) } )
2015-02-13 14:40:36 -05:00
c . Type = Types [ TNIL ]
return c
}
2015-02-17 22:13:49 -05:00
func Nodbool ( b bool ) * Node {
2015-02-23 16:07:24 -05:00
c := Nodintconst ( 0 )
2015-05-27 00:47:05 -04:00
c . SetVal ( Val { b } )
2015-02-13 14:40:36 -05:00
c . Type = idealbool
return c
}
func aindex ( b * Node , t * Type ) * Type {
2015-02-23 16:07:24 -05:00
bound := int64 ( - 1 ) // open bound
2015-02-13 14:40:36 -05:00
typecheck ( & b , Erv )
if b != nil {
switch consttype ( b ) {
default :
Yyerror ( "array bound must be an integer expression" )
2015-04-01 09:38:44 -07:00
case CTINT , CTRUNE :
2015-05-27 00:47:05 -04:00
bound = Mpgetfix ( b . Val ( ) . U . ( * Mpint ) )
2015-02-13 14:40:36 -05:00
if bound < 0 {
Yyerror ( "array bound must be non negative" )
}
}
}
// fixed array
2015-02-23 16:07:24 -05:00
r := typ ( TARRAY )
2015-02-13 14:40:36 -05:00
r . Type = t
r . Bound = bound
return r
}
2015-05-22 22:01:01 -04:00
// treecopy recursively copies n, with the exception of
// ONAME, OLITERAL, OTYPE, and non-iota ONONAME leaves.
// Copies of iota ONONAME nodes are assigned the current
// value of iota_. If lineno != 0, it sets the line number
// of newly allocated nodes to lineno.
func treecopy ( n * Node , lineno int32 ) * Node {
2015-02-13 14:40:36 -05:00
if n == nil {
return nil
}
2015-02-23 16:07:24 -05:00
var m * Node
2015-02-13 14:40:36 -05:00
switch n . Op {
default :
m = Nod ( OXXX , nil , nil )
* m = * n
m . Orig = m
2015-05-22 22:01:01 -04:00
m . Left = treecopy ( n . Left , lineno )
m . Right = treecopy ( n . Right , lineno )
m . List = listtreecopy ( n . List , lineno )
2015-06-29 16:30:19 -04:00
if lineno != 0 {
2015-05-22 22:01:01 -04:00
m . Lineno = lineno
}
2015-05-27 00:44:05 -04:00
if m . Name != nil && n . Op != ODCLFIELD {
2015-05-26 22:19:27 -04:00
Dump ( "treecopy" , n )
2015-08-30 23:10:03 +02:00
Fatalf ( "treecopy Name" )
2015-02-13 14:40:36 -05:00
}
case ONONAME :
if n . Sym == Lookup ( "iota" ) {
// Not sure yet whether this is the real iota,
// but make a copy of the Node* just in case,
// so that all the copies of this const definition
// don't have the same iota value.
m = Nod ( OXXX , nil , nil )
* m = * n
2015-05-22 22:01:01 -04:00
if lineno != 0 {
m . Lineno = lineno
}
2015-05-26 23:56:14 -04:00
m . Name = new ( Name )
* m . Name = * n . Name
m . Name . Iota = iota_
2015-02-13 14:40:36 -05:00
break
}
fallthrough
2015-04-01 09:38:44 -07:00
case ONAME , OLITERAL , OTYPE :
2015-02-13 14:40:36 -05:00
m = n
}
return m
}
2015-12-04 14:44:27 -08:00
// isnil reports whether n represents the universal untyped zero value "nil".
2015-02-17 22:13:49 -05:00
func isnil ( n * Node ) bool {
2015-12-04 14:44:27 -08:00
// Check n.Orig because constant propagation may produce typed nil constants,
// which don't exist in the Go spec.
return Isconst ( n . Orig , CTNIL )
2015-02-13 14:40:36 -05:00
}
2015-09-24 23:21:18 +02:00
func isptrto ( t * Type , et EType ) bool {
2015-02-13 14:40:36 -05:00
if t == nil {
2015-02-17 22:13:49 -05:00
return false
2015-02-13 14:40:36 -05:00
}
2015-03-01 07:54:01 +00:00
if ! Isptr [ t . Etype ] {
2015-02-17 22:13:49 -05:00
return false
2015-02-13 14:40:36 -05:00
}
t = t . Type
if t == nil {
2015-02-17 22:13:49 -05:00
return false
2015-02-13 14:40:36 -05:00
}
2015-09-24 23:21:18 +02:00
if t . Etype != et {
2015-02-17 22:13:49 -05:00
return false
2015-02-13 14:40:36 -05:00
}
2015-02-17 22:13:49 -05:00
return true
2015-02-13 14:40:36 -05:00
}
2015-09-24 23:21:18 +02:00
func Istype ( t * Type , et EType ) bool {
return t != nil && t . Etype == et
2015-02-13 14:40:36 -05:00
}
2015-02-17 22:13:49 -05:00
func Isfixedarray ( t * Type ) bool {
return t != nil && t . Etype == TARRAY && t . Bound >= 0
2015-02-13 14:40:36 -05:00
}
2015-02-17 22:13:49 -05:00
func Isslice ( t * Type ) bool {
return t != nil && t . Etype == TARRAY && t . Bound < 0
2015-02-13 14:40:36 -05:00
}
func isblank ( n * Node ) bool {
if n == nil {
return false
}
return isblanksym ( n . Sym )
}
func isblanksym ( s * Sym ) bool {
return s != nil && s . Name == "_"
}
2015-02-17 22:13:49 -05:00
func Isinter ( t * Type ) bool {
return t != nil && t . Etype == TINTER
2015-02-13 14:40:36 -05:00
}
2015-02-17 22:13:49 -05:00
func isnilinter ( t * Type ) bool {
if ! Isinter ( t ) {
return false
2015-02-13 14:40:36 -05:00
}
if t . Type != nil {
2015-02-17 22:13:49 -05:00
return false
2015-02-13 14:40:36 -05:00
}
2015-02-17 22:13:49 -05:00
return true
2015-02-13 14:40:36 -05:00
}
2015-02-17 22:13:49 -05:00
func isideal ( t * Type ) bool {
2015-02-13 14:40:36 -05:00
if t == nil {
2015-02-17 22:13:49 -05:00
return false
2015-02-13 14:40:36 -05:00
}
if t == idealstring || t == idealbool {
2015-02-17 22:13:49 -05:00
return true
2015-02-13 14:40:36 -05:00
}
switch t . Etype {
2015-04-01 09:38:44 -07:00
case TNIL , TIDEAL :
2015-02-17 22:13:49 -05:00
return true
2015-02-13 14:40:36 -05:00
}
2015-02-17 22:13:49 -05:00
return false
2015-02-13 14:40:36 -05:00
}
2015-10-22 09:51:12 +09:00
// given receiver of type t (t == r or t == *r)
// return type to hang methods off (r).
2015-02-13 14:40:36 -05:00
func methtype ( t * Type , mustname int ) * Type {
if t == nil {
return nil
}
// strip away pointer if it's there
2015-03-01 07:54:01 +00:00
if Isptr [ t . Etype ] {
2015-02-13 14:40:36 -05:00
if t . Sym != nil {
return nil
}
t = t . Type
if t == nil {
return nil
}
}
// need a type name
if t . Sym == nil && ( mustname != 0 || t . Etype != TSTRUCT ) {
return nil
}
// check types
2015-03-01 07:54:01 +00:00
if ! issimple [ t . Etype ] {
2015-02-13 14:40:36 -05:00
switch t . Etype {
default :
return nil
case TSTRUCT ,
TARRAY ,
TMAP ,
TCHAN ,
TSTRING ,
TFUNC :
break
}
}
return t
}
2015-09-24 23:21:18 +02:00
func cplxsubtype ( et EType ) EType {
2015-02-13 14:40:36 -05:00
switch et {
case TCOMPLEX64 :
return TFLOAT32
case TCOMPLEX128 :
return TFLOAT64
}
2015-09-24 23:21:18 +02:00
Fatalf ( "cplxsubtype: %v\n" , Econv ( et ) )
2015-02-13 14:40:36 -05:00
return 0
}
2015-03-02 16:03:26 -05:00
func eqnote ( a , b * string ) bool {
return a == b || a != nil && b != nil && * a == * b
2015-02-13 14:40:36 -05:00
}
type TypePairList struct {
t1 * Type
t2 * Type
next * TypePairList
}
2015-02-17 22:13:49 -05:00
func onlist ( l * TypePairList , t1 * Type , t2 * Type ) bool {
2015-02-13 14:40:36 -05:00
for ; l != nil ; l = l . next {
if ( l . t1 == t1 && l . t2 == t2 ) || ( l . t1 == t2 && l . t2 == t1 ) {
2015-02-17 22:13:49 -05:00
return true
2015-02-13 14:40:36 -05:00
}
}
2015-02-17 22:13:49 -05:00
return false
2015-02-13 14:40:36 -05:00
}
// Return 1 if t1 and t2 are identical, following the spec rules.
//
// Any cyclic type must go through a named type, and if one is
// named, it is only identical to the other if they are the same
// pointer (t1 == t2), so there's no chance of chasing cycles
// ad infinitum, so no need for a depth counter.
func Eqtype ( t1 * Type , t2 * Type ) bool {
2015-02-17 22:13:49 -05:00
return eqtype1 ( t1 , t2 , nil )
2015-02-13 14:40:36 -05:00
}
2015-02-17 22:13:49 -05:00
func eqtype1 ( t1 * Type , t2 * Type , assumed_equal * TypePairList ) bool {
2015-02-13 14:40:36 -05:00
if t1 == t2 {
2015-02-17 22:13:49 -05:00
return true
2015-02-13 14:40:36 -05:00
}
if t1 == nil || t2 == nil || t1 . Etype != t2 . Etype {
2015-02-17 22:13:49 -05:00
return false
2015-02-13 14:40:36 -05:00
}
if t1 . Sym != nil || t2 . Sym != nil {
// Special case: we keep byte and uint8 separate
// for error messages. Treat them as equal.
switch t1 . Etype {
case TUINT8 :
if ( t1 == Types [ TUINT8 ] || t1 == bytetype ) && ( t2 == Types [ TUINT8 ] || t2 == bytetype ) {
2015-02-17 22:13:49 -05:00
return true
2015-02-13 14:40:36 -05:00
}
2015-04-01 09:38:44 -07:00
case TINT , TINT32 :
2015-02-13 14:40:36 -05:00
if ( t1 == Types [ runetype . Etype ] || t1 == runetype ) && ( t2 == Types [ runetype . Etype ] || t2 == runetype ) {
2015-02-17 22:13:49 -05:00
return true
2015-02-13 14:40:36 -05:00
}
}
2015-02-17 22:13:49 -05:00
return false
2015-02-13 14:40:36 -05:00
}
2015-02-17 22:13:49 -05:00
if onlist ( assumed_equal , t1 , t2 ) {
return true
2015-02-13 14:40:36 -05:00
}
2015-02-23 16:07:24 -05:00
var l TypePairList
2015-02-13 14:40:36 -05:00
l . next = assumed_equal
l . t1 = t1
l . t2 = t2
switch t1 . Etype {
2015-04-01 09:38:44 -07:00
case TINTER , TSTRUCT :
2015-02-13 14:40:36 -05:00
t1 = t1 . Type
t2 = t2 . Type
2015-03-09 00:31:13 -04:00
for ; t1 != nil && t2 != nil ; t1 , t2 = t1 . Down , t2 . Down {
2015-02-13 14:40:36 -05:00
if t1 . Etype != TFIELD || t2 . Etype != TFIELD {
2015-08-30 23:10:03 +02:00
Fatalf ( "struct/interface missing field: %v %v" , t1 , t2 )
2015-02-13 14:40:36 -05:00
}
2015-02-17 22:13:49 -05:00
if t1 . Sym != t2 . Sym || t1 . Embedded != t2 . Embedded || ! eqtype1 ( t1 . Type , t2 . Type , & l ) || ! eqnote ( t1 . Note , t2 . Note ) {
2015-03-02 12:35:15 -05:00
return false
2015-02-13 14:40:36 -05:00
}
}
if t1 == nil && t2 == nil {
2015-03-02 12:35:15 -05:00
return true
2015-02-13 14:40:36 -05:00
}
2015-03-02 12:35:15 -05:00
return false
2015-02-13 14:40:36 -05:00
// Loop over structs: receiver, in, out.
case TFUNC :
t1 = t1 . Type
t2 = t2 . Type
2015-03-09 00:31:13 -04:00
for ; t1 != nil && t2 != nil ; t1 , t2 = t1 . Down , t2 . Down {
2015-02-13 14:40:36 -05:00
if t1 . Etype != TSTRUCT || t2 . Etype != TSTRUCT {
2015-08-30 23:10:03 +02:00
Fatalf ( "func missing struct: %v %v" , t1 , t2 )
2015-02-13 14:40:36 -05:00
}
// Loop over fields in structs, ignoring argument names.
2015-03-12 18:45:30 -04:00
ta := t1 . Type
tb := t2 . Type
2015-03-09 00:31:13 -04:00
for ; ta != nil && tb != nil ; ta , tb = ta . Down , tb . Down {
2015-02-13 14:40:36 -05:00
if ta . Etype != TFIELD || tb . Etype != TFIELD {
2015-08-30 23:10:03 +02:00
Fatalf ( "func struct missing field: %v %v" , ta , tb )
2015-02-13 14:40:36 -05:00
}
2015-02-17 22:13:49 -05:00
if ta . Isddd != tb . Isddd || ! eqtype1 ( ta . Type , tb . Type , & l ) {
2015-03-02 12:35:15 -05:00
return false
2015-02-13 14:40:36 -05:00
}
}
if ta != nil || tb != nil {
2015-03-02 12:35:15 -05:00
return false
2015-02-13 14:40:36 -05:00
}
}
if t1 == nil && t2 == nil {
2015-03-02 12:35:15 -05:00
return true
2015-02-13 14:40:36 -05:00
}
2015-03-02 12:35:15 -05:00
return false
2015-02-13 14:40:36 -05:00
case TARRAY :
if t1 . Bound != t2 . Bound {
2015-03-02 12:35:15 -05:00
return false
2015-02-13 14:40:36 -05:00
}
case TCHAN :
if t1 . Chan != t2 . Chan {
2015-03-02 12:35:15 -05:00
return false
2015-02-13 14:40:36 -05:00
}
}
2015-02-17 22:13:49 -05:00
if eqtype1 ( t1 . Down , t2 . Down , & l ) && eqtype1 ( t1 . Type , t2 . Type , & l ) {
2015-03-02 12:35:15 -05:00
return true
2015-02-13 14:40:36 -05:00
}
2015-02-17 22:13:49 -05:00
return false
2015-02-13 14:40:36 -05:00
}
// Are t1 and t2 equal struct types when field names are ignored?
// For deciding whether the result struct from g can be copied
// directly when compiling f(g()).
2015-02-17 22:13:49 -05:00
func eqtypenoname ( t1 * Type , t2 * Type ) bool {
2015-02-13 14:40:36 -05:00
if t1 == nil || t2 == nil || t1 . Etype != TSTRUCT || t2 . Etype != TSTRUCT {
2015-02-17 22:13:49 -05:00
return false
2015-02-13 14:40:36 -05:00
}
t1 = t1 . Type
t2 = t2 . Type
for {
if ! Eqtype ( t1 , t2 ) {
2015-02-17 22:13:49 -05:00
return false
2015-02-13 14:40:36 -05:00
}
if t1 == nil {
2015-02-17 22:13:49 -05:00
return true
2015-02-13 14:40:36 -05:00
}
t1 = t1 . Down
t2 = t2 . Down
}
}
// Is type src assignment compatible to type dst?
// If so, return op code to use in conversion.
// If not, return 0.
2015-09-24 23:21:18 +02:00
func assignop ( src * Type , dst * Type , why * string ) Op {
2015-02-13 14:40:36 -05:00
if why != nil {
* why = ""
}
// TODO(rsc,lvd): This behaves poorly in the presence of inlining.
// https://golang.org/issue/2795
if safemode != 0 && importpkg == nil && src != nil && src . Etype == TUNSAFEPTR {
Yyerror ( "cannot use unsafe.Pointer" )
errorexit ( )
}
if src == dst {
return OCONVNOP
}
if src == nil || dst == nil || src . Etype == TFORW || dst . Etype == TFORW || src . Orig == nil || dst . Orig == nil {
return 0
}
// 1. src type is identical to dst.
if Eqtype ( src , dst ) {
return OCONVNOP
}
// 2. src and dst have identical underlying types
// and either src or dst is not a named type or
// both are empty interface types.
// For assignable but different non-empty interface types,
// we want to recompute the itab.
2015-02-17 22:13:49 -05:00
if Eqtype ( src . Orig , dst . Orig ) && ( src . Sym == nil || dst . Sym == nil || isnilinter ( src ) ) {
2015-02-13 14:40:36 -05:00
return OCONVNOP
}
// 3. dst is an interface type and src implements dst.
if dst . Etype == TINTER && src . Etype != TNIL {
2015-02-23 16:07:24 -05:00
var missing * Type
var ptr int
var have * Type
2015-02-17 22:13:49 -05:00
if implements ( src , dst , & missing , & have , & ptr ) {
2015-02-13 14:40:36 -05:00
return OCONVIFACE
}
// we'll have complained about this method anyway, suppress spurious messages.
2015-09-07 10:37:26 +10:00
if have != nil && have . Sym == missing . Sym && ( have . Type . Broke || missing . Type . Broke ) {
2015-02-13 14:40:36 -05:00
return OCONVIFACE
}
if why != nil {
2015-02-17 22:13:49 -05:00
if isptrto ( src , TINTER ) {
2015-04-17 12:03:22 -04:00
* why = fmt . Sprintf ( ":\n\t%v is pointer to interface, not interface" , src )
2015-02-17 22:13:49 -05:00
} else if have != nil && have . Sym == missing . Sym && have . Nointerface {
2015-04-17 12:03:22 -04:00
* why = fmt . Sprintf ( ":\n\t%v does not implement %v (%v method is marked 'nointerface')" , src , dst , missing . Sym )
2015-02-13 14:40:36 -05:00
} else if have != nil && have . Sym == missing . Sym {
2015-04-17 12:03:22 -04:00
* why = fmt . Sprintf ( ":\n\t%v does not implement %v (wrong type for %v method)\n" + "\t\thave %v%v\n\t\twant %v%v" , src , dst , missing . Sym , have . Sym , Tconv ( have . Type , obj . FmtShort | obj . FmtByte ) , missing . Sym , Tconv ( missing . Type , obj . FmtShort | obj . FmtByte ) )
2015-02-13 14:40:36 -05:00
} else if ptr != 0 {
2015-04-17 12:03:22 -04:00
* why = fmt . Sprintf ( ":\n\t%v does not implement %v (%v method has pointer receiver)" , src , dst , missing . Sym )
2015-02-13 14:40:36 -05:00
} else if have != nil {
2015-04-17 12:03:22 -04:00
* why = fmt . Sprintf ( ":\n\t%v does not implement %v (missing %v method)\n" + "\t\thave %v%v\n\t\twant %v%v" , src , dst , missing . Sym , have . Sym , Tconv ( have . Type , obj . FmtShort | obj . FmtByte ) , missing . Sym , Tconv ( missing . Type , obj . FmtShort | obj . FmtByte ) )
2015-02-13 14:40:36 -05:00
} else {
2015-04-17 12:03:22 -04:00
* why = fmt . Sprintf ( ":\n\t%v does not implement %v (missing %v method)" , src , dst , missing . Sym )
2015-02-13 14:40:36 -05:00
}
}
return 0
}
2015-02-17 22:13:49 -05:00
if isptrto ( dst , TINTER ) {
2015-02-13 14:40:36 -05:00
if why != nil {
2015-04-17 12:03:22 -04:00
* why = fmt . Sprintf ( ":\n\t%v is pointer to interface, not interface" , dst )
2015-02-13 14:40:36 -05:00
}
return 0
}
if src . Etype == TINTER && dst . Etype != TBLANK {
2015-02-23 16:07:24 -05:00
var have * Type
var ptr int
var missing * Type
2015-02-17 22:13:49 -05:00
if why != nil && implements ( dst , src , & missing , & have , & ptr ) {
2015-02-13 14:40:36 -05:00
* why = ": need type assertion"
}
return 0
}
// 4. src is a bidirectional channel value, dst is a channel type,
// src and dst have identical element types, and
// either src or dst is not a named type.
if src . Etype == TCHAN && src . Chan == Cboth && dst . Etype == TCHAN {
if Eqtype ( src . Type , dst . Type ) && ( src . Sym == nil || dst . Sym == nil ) {
return OCONVNOP
}
}
// 5. src is the predeclared identifier nil and dst is a nillable type.
if src . Etype == TNIL {
switch dst . Etype {
case TARRAY :
if dst . Bound != - 100 { // not slice
break
}
fallthrough
case TPTR32 ,
TPTR64 ,
TFUNC ,
TMAP ,
TCHAN ,
TINTER :
return OCONVNOP
}
}
// 6. rule about untyped constants - already converted by defaultlit.
// 7. Any typed value can be assigned to the blank identifier.
if dst . Etype == TBLANK {
return OCONVNOP
}
return 0
}
// Can we convert a value of type src to a value of type dst?
// If so, return op code to use in conversion (maybe OCONVNOP).
// If not, return 0.
2015-09-24 23:21:18 +02:00
func convertop ( src * Type , dst * Type , why * string ) Op {
2015-02-13 14:40:36 -05:00
if why != nil {
* why = ""
}
if src == dst {
return OCONVNOP
}
if src == nil || dst == nil {
return 0
}
// 1. src can be assigned to dst.
2015-02-23 16:07:24 -05:00
op := assignop ( src , dst , why )
2015-02-13 14:40:36 -05:00
if op != 0 {
return op
}
// The rules for interfaces are no different in conversions
// than assignments. If interfaces are involved, stop now
// with the good message from assignop.
// Otherwise clear the error.
if src . Etype == TINTER || dst . Etype == TINTER {
return 0
}
if why != nil {
* why = ""
}
// 2. src and dst have identical underlying types.
if Eqtype ( src . Orig , dst . Orig ) {
return OCONVNOP
}
// 3. src and dst are unnamed pointer types
// and their base types have identical underlying types.
2015-03-01 07:54:01 +00:00
if Isptr [ src . Etype ] && Isptr [ dst . Etype ] && src . Sym == nil && dst . Sym == nil {
2015-02-13 14:40:36 -05:00
if Eqtype ( src . Type . Orig , dst . Type . Orig ) {
return OCONVNOP
}
}
// 4. src and dst are both integer or floating point types.
2015-03-01 07:54:01 +00:00
if ( Isint [ src . Etype ] || Isfloat [ src . Etype ] ) && ( Isint [ dst . Etype ] || Isfloat [ dst . Etype ] ) {
2015-02-13 14:40:36 -05:00
if Simtype [ src . Etype ] == Simtype [ dst . Etype ] {
return OCONVNOP
}
return OCONV
}
// 5. src and dst are both complex types.
2015-03-01 07:54:01 +00:00
if Iscomplex [ src . Etype ] && Iscomplex [ dst . Etype ] {
2015-02-13 14:40:36 -05:00
if Simtype [ src . Etype ] == Simtype [ dst . Etype ] {
return OCONVNOP
}
return OCONV
}
// 6. src is an integer or has type []byte or []rune
// and dst is a string type.
2015-03-01 07:54:01 +00:00
if Isint [ src . Etype ] && dst . Etype == TSTRING {
2015-02-13 14:40:36 -05:00
return ORUNESTR
}
2015-02-17 22:13:49 -05:00
if Isslice ( src ) && dst . Etype == TSTRING {
2015-02-13 14:40:36 -05:00
if src . Type . Etype == bytetype . Etype {
return OARRAYBYTESTR
}
if src . Type . Etype == runetype . Etype {
return OARRAYRUNESTR
}
}
// 7. src is a string and dst is []byte or []rune.
// String to slice.
2015-02-17 22:13:49 -05:00
if src . Etype == TSTRING && Isslice ( dst ) {
2015-02-13 14:40:36 -05:00
if dst . Type . Etype == bytetype . Etype {
return OSTRARRAYBYTE
}
if dst . Type . Etype == runetype . Etype {
return OSTRARRAYRUNE
}
}
// 8. src is a pointer or uintptr and dst is unsafe.Pointer.
2015-03-01 07:54:01 +00:00
if ( Isptr [ src . Etype ] || src . Etype == TUINTPTR ) && dst . Etype == TUNSAFEPTR {
2015-02-13 14:40:36 -05:00
return OCONVNOP
}
// 9. src is unsafe.Pointer and dst is a pointer or uintptr.
2015-03-01 07:54:01 +00:00
if src . Etype == TUNSAFEPTR && ( Isptr [ dst . Etype ] || dst . Etype == TUINTPTR ) {
2015-02-13 14:40:36 -05:00
return OCONVNOP
}
return 0
}
func assignconv ( n * Node , t * Type , context string ) * Node {
2015-03-12 18:45:30 -04:00
return assignconvfn ( n , t , func ( ) string { return context } )
}
// Convert node n for assignment to type t.
func assignconvfn ( n * Node , t * Type , context func ( ) string ) * Node {
2015-09-07 10:37:26 +10:00
if n == nil || n . Type == nil || n . Type . Broke {
2015-02-13 14:40:36 -05:00
return n
}
if t . Etype == TBLANK && n . Type . Etype == TNIL {
Yyerror ( "use of untyped nil" )
}
2015-02-23 16:07:24 -05:00
old := n
2015-02-13 14:40:36 -05:00
old . Diag ++ // silence errors about n; we'll issue one below
defaultlit ( & n , t )
old . Diag --
if t . Etype == TBLANK {
return n
}
// Convert ideal bool from comparison to plain bool
// if the next step is non-bool (like interface{}).
if n . Type == idealbool && t . Etype != TBOOL {
if n . Op == ONAME || n . Op == OLITERAL {
2015-02-23 16:07:24 -05:00
r := Nod ( OCONVNOP , n , nil )
2015-02-13 14:40:36 -05:00
r . Type = Types [ TBOOL ]
r . Typecheck = 1
2015-03-06 21:18:41 +11:00
r . Implicit = true
2015-02-13 14:40:36 -05:00
n = r
}
}
if Eqtype ( n . Type , t ) {
return n
}
2015-02-23 16:07:24 -05:00
var why string
op := assignop ( n . Type , t , & why )
2015-02-13 14:40:36 -05:00
if op == 0 {
2015-04-17 12:03:22 -04:00
Yyerror ( "cannot use %v as type %v in %s%s" , Nconv ( n , obj . FmtLong ) , t , context ( ) , why )
2015-02-13 14:40:36 -05:00
op = OCONV
}
2015-02-23 16:07:24 -05:00
r := Nod ( op , n , nil )
2015-02-13 14:40:36 -05:00
r . Type = t
r . Typecheck = 1
2015-03-06 21:18:41 +11:00
r . Implicit = true
2015-02-13 14:40:36 -05:00
r . Orig = n . Orig
return r
}
2015-03-08 13:33:49 -04:00
// substArgTypes substitutes the given list of types for
// successive occurrences of the "any" placeholder in the
// type syntax expression n.Type.
func substArgTypes ( n * Node , types ... * Type ) {
for _ , t := range types {
dowidth ( t )
2015-02-13 14:40:36 -05:00
}
2015-03-08 13:33:49 -04:00
substAny ( & n . Type , & types )
if len ( types ) > 0 {
2015-08-30 23:10:03 +02:00
Fatalf ( "substArgTypes: too many argument types" )
2015-02-13 14:40:36 -05:00
}
2015-03-08 13:33:49 -04:00
}
2015-02-13 14:40:36 -05:00
2015-03-08 13:33:49 -04:00
// substAny walks *tp, replacing instances of "any" with successive
// elements removed from types.
func substAny ( tp * * Type , types * [ ] * Type ) {
for {
t := * tp
if t == nil {
return
2015-02-13 14:40:36 -05:00
}
2015-09-08 03:51:30 +02:00
if t . Etype == TANY && t . Copyany {
2015-03-08 13:33:49 -04:00
if len ( * types ) == 0 {
2015-08-30 23:10:03 +02:00
Fatalf ( "substArgTypes: not enough argument types" )
2015-02-13 14:40:36 -05:00
}
2015-03-08 13:33:49 -04:00
* tp = ( * types ) [ 0 ]
* types = ( * types ) [ 1 : ]
2015-02-13 14:40:36 -05:00
}
2015-03-08 13:33:49 -04:00
switch t . Etype {
case TPTR32 , TPTR64 , TCHAN , TARRAY :
tp = & t . Type
continue
case TMAP :
substAny ( & t . Down , types )
tp = & t . Type
continue
case TFUNC :
substAny ( & t . Type , types )
substAny ( & t . Type . Down . Down , types )
substAny ( & t . Type . Down , types )
case TSTRUCT :
for t = t . Type ; t != nil ; t = t . Down {
substAny ( & t . Type , types )
2015-02-13 14:40:36 -05:00
}
}
2015-03-08 13:33:49 -04:00
return
2015-02-13 14:40:36 -05:00
}
}
2015-10-22 09:51:12 +09:00
// Is this a 64-bit type?
2015-02-17 22:13:49 -05:00
func Is64 ( t * Type ) bool {
2015-02-13 14:40:36 -05:00
if t == nil {
2015-02-17 22:13:49 -05:00
return false
2015-02-13 14:40:36 -05:00
}
switch Simtype [ t . Etype ] {
2015-04-01 09:38:44 -07:00
case TINT64 , TUINT64 , TPTR64 :
2015-02-17 22:13:49 -05:00
return true
2015-02-13 14:40:36 -05:00
}
2015-02-17 22:13:49 -05:00
return false
2015-02-13 14:40:36 -05:00
}
2015-10-22 09:51:12 +09:00
// Is a conversion between t1 and t2 a no-op?
2015-02-17 22:13:49 -05:00
func Noconv ( t1 * Type , t2 * Type ) bool {
2015-09-24 23:21:18 +02:00
e1 := Simtype [ t1 . Etype ]
e2 := Simtype [ t2 . Etype ]
2015-02-13 14:40:36 -05:00
switch e1 {
2015-04-01 09:38:44 -07:00
case TINT8 , TUINT8 :
2015-02-17 22:13:49 -05:00
return e2 == TINT8 || e2 == TUINT8
2015-02-13 14:40:36 -05:00
2015-04-01 09:38:44 -07:00
case TINT16 , TUINT16 :
2015-02-17 22:13:49 -05:00
return e2 == TINT16 || e2 == TUINT16
2015-02-13 14:40:36 -05:00
2015-04-01 09:38:44 -07:00
case TINT32 , TUINT32 , TPTR32 :
2015-02-17 22:13:49 -05:00
return e2 == TINT32 || e2 == TUINT32 || e2 == TPTR32
2015-02-13 14:40:36 -05:00
2015-04-01 09:38:44 -07:00
case TINT64 , TUINT64 , TPTR64 :
2015-02-17 22:13:49 -05:00
return e2 == TINT64 || e2 == TUINT64 || e2 == TPTR64
2015-02-13 14:40:36 -05:00
case TFLOAT32 :
2015-02-17 22:13:49 -05:00
return e2 == TFLOAT32
2015-02-13 14:40:36 -05:00
case TFLOAT64 :
2015-02-17 22:13:49 -05:00
return e2 == TFLOAT64
2015-02-13 14:40:36 -05:00
}
2015-02-17 22:13:49 -05:00
return false
2015-02-13 14:40:36 -05:00
}
func shallow ( t * Type ) * Type {
if t == nil {
return nil
}
2015-02-23 16:07:24 -05:00
nt := typ ( 0 )
2015-02-13 14:40:36 -05:00
* nt = * t
if t . Orig == t {
nt . Orig = nt
}
return nt
}
func deep ( t * Type ) * Type {
if t == nil {
return nil
}
2015-02-23 16:07:24 -05:00
var nt * Type
2015-02-13 14:40:36 -05:00
switch t . Etype {
default :
nt = t // share from here down
2016-02-23 07:46:01 +00:00
case TANY :
nt = shallow ( t )
nt . Copyany = true
2015-04-01 09:38:44 -07:00
case TPTR32 , TPTR64 , TCHAN , TARRAY :
2015-02-13 14:40:36 -05:00
nt = shallow ( t )
nt . Type = deep ( t . Type )
case TMAP :
nt = shallow ( t )
nt . Down = deep ( t . Down )
nt . Type = deep ( t . Type )
case TFUNC :
nt = shallow ( t )
nt . Type = deep ( t . Type )
nt . Type . Down = deep ( t . Type . Down )
nt . Type . Down . Down = deep ( t . Type . Down . Down )
case TSTRUCT :
nt = shallow ( t )
nt . Type = shallow ( t . Type )
2015-02-23 16:07:24 -05:00
xt := nt . Type
2015-02-13 14:40:36 -05:00
for t = t . Type ; t != nil ; t = t . Down {
xt . Type = deep ( t . Type )
xt . Down = shallow ( t . Down )
xt = xt . Down
}
}
return nt
}
func syslook ( name string , copy int ) * Node {
2015-02-23 16:07:24 -05:00
s := Pkglookup ( name , Runtimepkg )
2015-02-13 14:40:36 -05:00
if s == nil || s . Def == nil {
2015-08-30 23:10:03 +02:00
Fatalf ( "syslook: can't find runtime.%s" , name )
2015-02-13 14:40:36 -05:00
}
2015-02-17 22:13:49 -05:00
if copy == 0 {
2015-02-13 14:40:36 -05:00
return s . Def
}
2015-02-23 16:07:24 -05:00
n := Nod ( 0 , nil , nil )
2015-02-13 14:40:36 -05:00
* n = * s . Def
n . Type = deep ( s . Def . Type )
return n
}
2015-10-22 09:51:12 +09:00
// compute a hash value for type t.
// if t is a method type, ignore the receiver
// so that the hash can be used in interface checks.
// %T already contains
// all the necessary logic to generate a representation
// of the type that completely describes it.
// using smprint here avoids duplicating that code.
// using md5 here is overkill, but i got tired of
// accidental collisions making the runtime think
// two types are equal when they really aren't.
2015-02-13 14:40:36 -05:00
func typehash ( t * Type ) uint32 {
var p string
if t . Thistuple != 0 {
// hide method receiver from Tpretty
t . Thistuple = 0
2015-03-12 18:45:30 -04:00
p = Tconv ( t , obj . FmtLeft | obj . FmtUnsigned )
2015-02-13 14:40:36 -05:00
t . Thistuple = 1
} else {
2015-03-12 18:45:30 -04:00
p = Tconv ( t , obj . FmtLeft | obj . FmtUnsigned )
2015-02-13 14:40:36 -05:00
}
//print("typehash: %s\n", p);
2015-02-27 16:05:30 +09:00
h := md5 . Sum ( [ ] byte ( p ) )
return binary . LittleEndian . Uint32 ( h [ : 4 ] )
2015-02-13 14:40:36 -05:00
}
2015-04-28 17:08:28 -07:00
var initPtrtoDone bool
var (
ptrToUint8 * Type
ptrToAny * Type
ptrToString * Type
ptrToBool * Type
ptrToInt32 * Type
)
func initPtrto ( ) {
ptrToUint8 = ptrto1 ( Types [ TUINT8 ] )
ptrToAny = ptrto1 ( Types [ TANY ] )
ptrToString = ptrto1 ( Types [ TSTRING ] )
ptrToBool = ptrto1 ( Types [ TBOOL ] )
ptrToInt32 = ptrto1 ( Types [ TINT32 ] )
}
func ptrto1 ( t * Type ) * Type {
2015-02-23 16:07:24 -05:00
t1 := typ ( Tptr )
2015-02-13 14:40:36 -05:00
t1 . Type = t
t1 . Width = int64 ( Widthptr )
t1 . Align = uint8 ( Widthptr )
return t1
}
2015-04-28 17:08:28 -07:00
// Ptrto returns the Type *t.
// The returned struct must not be modified.
func Ptrto ( t * Type ) * Type {
if Tptr == 0 {
2015-08-30 23:10:03 +02:00
Fatalf ( "ptrto: no tptr" )
2015-04-28 17:08:28 -07:00
}
// Reduce allocations by pre-creating common cases.
if ! initPtrtoDone {
initPtrto ( )
initPtrtoDone = true
}
switch t {
case Types [ TUINT8 ] :
return ptrToUint8
case Types [ TINT32 ] :
return ptrToInt32
case Types [ TANY ] :
return ptrToAny
case Types [ TSTRING ] :
return ptrToString
case Types [ TBOOL ] :
return ptrToBool
}
return ptrto1 ( t )
}
2015-02-13 14:40:36 -05:00
func frame ( context int ) {
if context != 0 {
fmt . Printf ( "--- external frame ---\n" )
2015-09-10 15:57:39 +10:00
for _ , n := range externdcl {
printframenode ( n )
}
2015-02-13 14:40:36 -05:00
return
}
2015-09-10 15:57:39 +10:00
if Curfn != nil {
fmt . Printf ( "--- %v frame ---\n" , Curfn . Func . Nname . Sym )
for l := Curfn . Func . Dcl ; l != nil ; l = l . Next {
printframenode ( l . N )
2015-02-13 14:40:36 -05:00
}
2015-09-10 15:57:39 +10:00
}
}
2015-02-13 14:40:36 -05:00
2015-09-10 15:57:39 +10:00
func printframenode ( n * Node ) {
w := int64 ( - 1 )
if n . Type != nil {
w = n . Type . Width
}
switch n . Op {
case ONAME :
fmt . Printf ( "%v %v G%d %v width=%d\n" , Oconv ( int ( n . Op ) , 0 ) , n . Sym , n . Name . Vargen , n . Type , w )
case OTYPE :
fmt . Printf ( "%v %v width=%d\n" , Oconv ( int ( n . Op ) , 0 ) , n . Type , w )
2015-02-13 14:40:36 -05:00
}
}
2015-10-22 09:51:12 +09:00
// calculate sethi/ullman number
// roughly how many registers needed to
// compile a node. used to compile the
// hardest side first to minimize registers.
2015-02-13 14:40:36 -05:00
func ullmancalc ( n * Node ) {
if n == nil {
return
}
2015-02-23 16:07:24 -05:00
var ul int
var ur int
2015-02-13 14:40:36 -05:00
if n . Ninit != nil {
ul = UINF
goto out
}
switch n . Op {
2015-04-01 09:38:44 -07:00
case OREGISTER , OLITERAL , ONAME :
2015-02-13 14:40:36 -05:00
ul = 1
if n . Class == PPARAMREF || ( n . Class & PHEAP != 0 ) {
ul ++
}
goto out
cmd/internal/gc: emit write barriers at lower level
This is primarily preparation for inlining, not an optimization by itself,
but it still helps some.
name old new delta
BenchmarkBinaryTree17 18.2s × (0.99,1.01) 17.9s × (0.99,1.01) -1.57%
BenchmarkFannkuch11 4.44s × (1.00,1.00) 4.42s × (1.00,1.00) -0.40%
BenchmarkFmtFprintfEmpty 119ns × (0.95,1.02) 118ns × (0.96,1.02) ~
BenchmarkFmtFprintfString 501ns × (0.99,1.02) 486ns × (0.99,1.01) -2.89%
BenchmarkFmtFprintfInt 474ns × (0.99,1.00) 457ns × (0.99,1.01) -3.59%
BenchmarkFmtFprintfIntInt 792ns × (1.00,1.00) 768ns × (1.00,1.01) -3.03%
BenchmarkFmtFprintfPrefixedInt 574ns × (1.00,1.01) 584ns × (0.99,1.03) +1.83%
BenchmarkFmtFprintfFloat 749ns × (1.00,1.00) 739ns × (0.99,1.00) -1.34%
BenchmarkFmtManyArgs 2.94µs × (1.00,1.01) 2.77µs × (1.00,1.00) -5.76%
BenchmarkGobDecode 39.5ms × (0.99,1.01) 39.3ms × (0.99,1.01) ~
BenchmarkGobEncode 39.4ms × (1.00,1.01) 39.4ms × (0.99,1.00) ~
BenchmarkGzip 658ms × (1.00,1.01) 661ms × (0.99,1.01) ~
BenchmarkGunzip 142ms × (1.00,1.00) 142ms × (1.00,1.00) +0.22%
BenchmarkHTTPClientServer 134µs × (0.99,1.01) 133µs × (0.98,1.01) ~
BenchmarkJSONEncode 57.1ms × (0.99,1.01) 56.5ms × (0.99,1.01) ~
BenchmarkJSONDecode 141ms × (1.00,1.00) 143ms × (1.00,1.00) +1.09%
BenchmarkMandelbrot200 6.01ms × (1.00,1.00) 6.01ms × (1.00,1.00) ~
BenchmarkGoParse 10.1ms × (0.91,1.09) 9.6ms × (0.94,1.07) ~
BenchmarkRegexpMatchEasy0_32 207ns × (1.00,1.01) 210ns × (1.00,1.00) +1.45%
BenchmarkRegexpMatchEasy0_1K 592ns × (0.99,1.00) 596ns × (0.99,1.01) +0.68%
BenchmarkRegexpMatchEasy1_32 184ns × (0.99,1.01) 184ns × (0.99,1.01) ~
BenchmarkRegexpMatchEasy1_1K 1.01µs × (1.00,1.00) 1.01µs × (0.99,1.01) ~
BenchmarkRegexpMatchMedium_32 327ns × (0.99,1.00) 327ns × (1.00,1.01) ~
BenchmarkRegexpMatchMedium_1K 92.5µs × (1.00,1.00) 93.0µs × (1.00,1.02) +0.48%
BenchmarkRegexpMatchHard_32 4.79µs × (0.95,1.00) 4.76µs × (0.95,1.01) ~
BenchmarkRegexpMatchHard_1K 136µs × (1.00,1.00) 136µs × (1.00,1.01) ~
BenchmarkRevcomp 900ms × (0.99,1.01) 892ms × (1.00,1.01) ~
BenchmarkTemplate 170ms × (0.99,1.01) 175ms × (0.99,1.00) +2.95%
BenchmarkTimeParse 645ns × (1.00,1.00) 638ns × (1.00,1.00) -1.16%
BenchmarkTimeFormat 740ns × (1.00,1.00) 772ns × (1.00,1.00) +4.39%
Change-Id: I0be905e32791e0cb70ff01f169c4b309a971d981
Reviewed-on: https://go-review.googlesource.com/9159
Reviewed-by: Rick Hudson <rlh@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2015-04-17 00:25:10 -04:00
case OCALL , OCALLFUNC , OCALLMETH , OCALLINTER , OASWB :
2015-02-13 14:40:36 -05:00
ul = UINF
goto out
2015-10-21 07:04:10 -07:00
// hard with instrumented code
2015-04-01 09:38:44 -07:00
case OANDAND , OOROR :
2015-10-20 10:00:07 -07:00
if instrumenting {
2015-02-13 14:40:36 -05:00
ul = UINF
goto out
}
}
ul = 1
if n . Left != nil {
ul = int ( n . Left . Ullman )
}
ur = 1
if n . Right != nil {
ur = int ( n . Right . Ullman )
}
if ul == ur {
ul += 1
}
if ur > ul {
ul = ur
}
out :
if ul > 200 {
ul = 200 // clamp to uchar with room to grow
}
n . Ullman = uint8 ( ul )
}
2015-09-24 23:21:18 +02:00
func badtype ( op Op , tl * Type , tr * Type ) {
2015-02-23 16:07:24 -05:00
fmt_ := ""
2015-02-13 14:40:36 -05:00
if tl != nil {
2015-04-17 12:03:22 -04:00
fmt_ += fmt . Sprintf ( "\n\t%v" , tl )
2015-02-13 14:40:36 -05:00
}
if tr != nil {
2015-04-17 12:03:22 -04:00
fmt_ += fmt . Sprintf ( "\n\t%v" , tr )
2015-02-13 14:40:36 -05:00
}
// common mistake: *struct and *interface.
2015-03-01 07:54:01 +00:00
if tl != nil && tr != nil && Isptr [ tl . Etype ] && Isptr [ tr . Etype ] {
2015-02-13 14:40:36 -05:00
if tl . Type . Etype == TSTRUCT && tr . Type . Etype == TINTER {
2015-02-28 20:31:32 +00:00
fmt_ += "\n\t(*struct vs *interface)"
2015-02-13 14:40:36 -05:00
} else if tl . Type . Etype == TINTER && tr . Type . Etype == TSTRUCT {
2015-02-28 20:31:32 +00:00
fmt_ += "\n\t(*interface vs *struct)"
2015-02-13 14:40:36 -05:00
}
}
2015-02-23 16:07:24 -05:00
s := fmt_
2015-09-24 23:21:18 +02:00
Yyerror ( "illegal types for operand: %v%s" , Oconv ( int ( op ) , 0 ) , s )
2015-02-13 14:40:36 -05:00
}
2015-10-22 09:51:12 +09:00
// iterator to walk a structure declaration
2015-02-13 14:40:36 -05:00
func Structfirst ( s * Iter , nn * * Type ) * Type {
var t * Type
2015-02-23 16:07:24 -05:00
n := * nn
2015-02-13 14:40:36 -05:00
if n == nil {
goto bad
}
switch n . Etype {
default :
goto bad
2015-04-01 09:38:44 -07:00
case TSTRUCT , TINTER , TFUNC :
2015-02-13 14:40:36 -05:00
break
}
t = n . Type
if t == nil {
2015-03-02 12:35:15 -05:00
return nil
2015-02-13 14:40:36 -05:00
}
if t . Etype != TFIELD {
2015-08-30 23:10:03 +02:00
Fatalf ( "structfirst: not field %v" , t )
2015-02-13 14:40:36 -05:00
}
s . T = t
return t
bad :
2015-08-30 23:10:03 +02:00
Fatalf ( "structfirst: not struct %v" , n )
2015-02-13 14:40:36 -05:00
return nil
}
func structnext ( s * Iter ) * Type {
2015-02-23 16:07:24 -05:00
n := s . T
t := n . Down
2015-02-13 14:40:36 -05:00
if t == nil {
2015-03-02 12:35:15 -05:00
return nil
2015-02-13 14:40:36 -05:00
}
if t . Etype != TFIELD {
2015-08-30 23:10:03 +02:00
Fatalf ( "structnext: not struct %v" , n )
2015-03-02 12:35:15 -05:00
return nil
2015-02-13 14:40:36 -05:00
}
s . T = t
return t
}
2015-10-22 09:51:12 +09:00
// iterator to this and inargs in a function
2015-02-13 14:40:36 -05:00
func funcfirst ( s * Iter , t * Type ) * Type {
var fp * Type
if t == nil {
goto bad
}
if t . Etype != TFUNC {
goto bad
}
s . Tfunc = t
s . Done = 0
fp = Structfirst ( s , getthis ( t ) )
if fp == nil {
s . Done = 1
fp = Structfirst ( s , getinarg ( t ) )
}
return fp
bad :
2015-08-30 23:10:03 +02:00
Fatalf ( "funcfirst: not func %v" , t )
2015-02-13 14:40:36 -05:00
return nil
}
func funcnext ( s * Iter ) * Type {
2015-02-23 16:07:24 -05:00
fp := structnext ( s )
2015-02-17 22:13:49 -05:00
if fp == nil && s . Done == 0 {
2015-02-13 14:40:36 -05:00
s . Done = 1
fp = Structfirst ( s , getinarg ( s . Tfunc ) )
}
return fp
}
func getthis ( t * Type ) * * Type {
if t . Etype != TFUNC {
2015-08-30 23:10:03 +02:00
Fatalf ( "getthis: not a func %v" , t )
2015-02-13 14:40:36 -05:00
}
return & t . Type
}
func Getoutarg ( t * Type ) * * Type {
if t . Etype != TFUNC {
2015-08-30 23:10:03 +02:00
Fatalf ( "getoutarg: not a func %v" , t )
2015-02-13 14:40:36 -05:00
}
return & t . Type . Down
}
func getinarg ( t * Type ) * * Type {
if t . Etype != TFUNC {
2015-08-30 23:10:03 +02:00
Fatalf ( "getinarg: not a func %v" , t )
2015-02-13 14:40:36 -05:00
}
return & t . Type . Down . Down
}
func getthisx ( t * Type ) * Type {
return * getthis ( t )
}
func getoutargx ( t * Type ) * Type {
return * Getoutarg ( t )
}
func getinargx ( t * Type ) * Type {
return * getinarg ( t )
}
2015-04-06 19:36:36 -07:00
// Brcom returns !(op).
// For example, Brcom(==) is !=.
2015-09-24 23:21:18 +02:00
func Brcom ( op Op ) Op {
switch op {
2015-02-13 14:40:36 -05:00
case OEQ :
return ONE
case ONE :
return OEQ
case OLT :
return OGE
case OGT :
return OLE
case OLE :
return OGT
case OGE :
return OLT
}
2015-09-24 23:21:18 +02:00
Fatalf ( "brcom: no com for %v\n" , Oconv ( int ( op ) , 0 ) )
return op
2015-02-13 14:40:36 -05:00
}
2015-04-06 19:36:36 -07:00
// Brrev returns reverse(op).
// For example, Brrev(<) is >.
2015-09-24 23:21:18 +02:00
func Brrev ( op Op ) Op {
switch op {
2015-02-13 14:40:36 -05:00
case OEQ :
return OEQ
case ONE :
return ONE
case OLT :
return OGT
case OGT :
return OLT
case OLE :
return OGE
case OGE :
return OLE
}
2015-09-24 23:21:18 +02:00
Fatalf ( "brrev: no rev for %v\n" , Oconv ( int ( op ) , 0 ) )
return op
2015-02-13 14:40:36 -05:00
}
2015-10-22 09:51:12 +09:00
// return side effect-free n, appending side effects to init.
// result is assignable if n is.
2015-02-13 14:40:36 -05:00
func safeexpr ( n * Node , init * * NodeList ) * Node {
if n == nil {
return nil
}
if n . Ninit != nil {
walkstmtlist ( n . Ninit )
* init = concat ( * init , n . Ninit )
n . Ninit = nil
}
switch n . Op {
2015-04-01 09:38:44 -07:00
case ONAME , OLITERAL :
2015-02-13 14:40:36 -05:00
return n
cmd/internal/gc: optimize slice + write barrier
The code generated for a slice x[i:j] or x[i:j:k] computes the entire
new slice (base, len, cap) and then uses it as the evaluation of the
slice expression.
If the slice is part of an update x = x[i:j] or x = x[i:j:k], there are
opportunities to avoid computing some of these fields.
For x = x[0:i], we know that only the len is changing;
base can be ignored completely, and cap can be left unmodified.
For x = x[0:i:j], we know that only len and cap are changing;
base can be ignored completely.
For x = x[i:i], we know that the resulting cap is zero, and we don't
adjust the base during a slice producing a zero-cap result,
so again base can be ignored completely.
No write to base, no write barrier.
The old slice code was trying to work at a Go syntax level, mainly
because that was how you wrote code just once instead of once
per architecture. Now the compiler is factored a bit better and we
can implement slice during code generation but still have one copy
of the code. So the new code is working at that lower level.
(It must, to update only parts of the result.)
This CL by itself:
name old mean new mean delta
BinaryTree17 5.81s × (0.98,1.03) 5.71s × (0.96,1.05) ~ (p=0.101)
Fannkuch11 4.35s × (1.00,1.00) 4.39s × (1.00,1.00) +0.79% (p=0.000)
FmtFprintfEmpty 86.0ns × (0.94,1.11) 82.6ns × (0.98,1.04) -3.86% (p=0.048)
FmtFprintfString 276ns × (0.98,1.04) 273ns × (0.98,1.02) ~ (p=0.235)
FmtFprintfInt 274ns × (0.98,1.06) 270ns × (0.99,1.01) ~ (p=0.119)
FmtFprintfIntInt 506ns × (0.99,1.01) 475ns × (0.99,1.01) -6.02% (p=0.000)
FmtFprintfPrefixedInt 391ns × (0.99,1.01) 393ns × (1.00,1.01) ~ (p=0.139)
FmtFprintfFloat 566ns × (0.99,1.01) 574ns × (1.00,1.01) +1.33% (p=0.001)
FmtManyArgs 1.91µs × (0.99,1.01) 1.87µs × (0.99,1.02) -1.83% (p=0.000)
GobDecode 15.3ms × (0.99,1.02) 15.0ms × (0.98,1.05) -1.84% (p=0.042)
GobEncode 11.5ms × (0.97,1.03) 11.4ms × (0.99,1.03) ~ (p=0.152)
Gzip 645ms × (0.99,1.01) 647ms × (0.99,1.01) ~ (p=0.265)
Gunzip 142ms × (1.00,1.00) 143ms × (1.00,1.01) +0.90% (p=0.000)
HTTPClientServer 90.5µs × (0.97,1.04) 88.5µs × (0.99,1.03) -2.27% (p=0.014)
JSONEncode 32.0ms × (0.98,1.03) 29.6ms × (0.98,1.01) -7.51% (p=0.000)
JSONDecode 114ms × (0.99,1.01) 104ms × (1.00,1.01) -8.60% (p=0.000)
Mandelbrot200 6.04ms × (1.00,1.01) 6.02ms × (1.00,1.00) ~ (p=0.057)
GoParse 6.47ms × (0.97,1.05) 6.37ms × (0.97,1.04) ~ (p=0.105)
RegexpMatchEasy0_32 171ns × (0.93,1.07) 152ns × (0.99,1.01) -11.09% (p=0.000)
RegexpMatchEasy0_1K 550ns × (0.98,1.01) 530ns × (1.00,1.00) -3.78% (p=0.000)
RegexpMatchEasy1_32 135ns × (0.99,1.02) 134ns × (0.99,1.01) -1.33% (p=0.002)
RegexpMatchEasy1_1K 879ns × (1.00,1.01) 865ns × (1.00,1.00) -1.58% (p=0.000)
RegexpMatchMedium_32 243ns × (1.00,1.00) 233ns × (1.00,1.00) -4.30% (p=0.000)
RegexpMatchMedium_1K 70.3µs × (1.00,1.00) 69.5µs × (1.00,1.00) -1.13% (p=0.000)
RegexpMatchHard_32 3.82µs × (1.00,1.01) 3.74µs × (1.00,1.00) -1.95% (p=0.000)
RegexpMatchHard_1K 117µs × (1.00,1.00) 115µs × (1.00,1.00) -1.69% (p=0.000)
Revcomp 917ms × (0.97,1.04) 920ms × (0.97,1.04) ~ (p=0.786)
Template 114ms × (0.99,1.01) 117ms × (0.99,1.01) +2.58% (p=0.000)
TimeParse 622ns × (0.99,1.01) 615ns × (0.99,1.00) -1.06% (p=0.000)
TimeFormat 665ns × (0.99,1.01) 654ns × (0.99,1.00) -1.70% (p=0.000)
This CL and previous CL (append) combined:
name old mean new mean delta
BinaryTree17 5.68s × (0.97,1.04) 5.71s × (0.96,1.05) ~ (p=0.638)
Fannkuch11 4.41s × (0.98,1.03) 4.39s × (1.00,1.00) ~ (p=0.474)
FmtFprintfEmpty 92.7ns × (0.91,1.16) 82.6ns × (0.98,1.04) -10.89% (p=0.004)
FmtFprintfString 281ns × (0.96,1.08) 273ns × (0.98,1.02) ~ (p=0.078)
FmtFprintfInt 288ns × (0.97,1.06) 270ns × (0.99,1.01) -6.37% (p=0.000)
FmtFprintfIntInt 493ns × (0.97,1.04) 475ns × (0.99,1.01) -3.53% (p=0.002)
FmtFprintfPrefixedInt 423ns × (0.97,1.04) 393ns × (1.00,1.01) -7.07% (p=0.000)
FmtFprintfFloat 598ns × (0.99,1.01) 574ns × (1.00,1.01) -4.02% (p=0.000)
FmtManyArgs 1.89µs × (0.98,1.05) 1.87µs × (0.99,1.02) ~ (p=0.305)
GobDecode 14.8ms × (0.98,1.03) 15.0ms × (0.98,1.05) ~ (p=0.237)
GobEncode 12.3ms × (0.98,1.01) 11.4ms × (0.99,1.03) -6.95% (p=0.000)
Gzip 656ms × (0.99,1.05) 647ms × (0.99,1.01) ~ (p=0.101)
Gunzip 142ms × (1.00,1.00) 143ms × (1.00,1.01) +0.58% (p=0.001)
HTTPClientServer 91.2µs × (0.97,1.04) 88.5µs × (0.99,1.03) -3.02% (p=0.003)
JSONEncode 32.6ms × (0.97,1.08) 29.6ms × (0.98,1.01) -9.10% (p=0.000)
JSONDecode 114ms × (0.97,1.05) 104ms × (1.00,1.01) -8.74% (p=0.000)
Mandelbrot200 6.11ms × (0.98,1.04) 6.02ms × (1.00,1.00) ~ (p=0.090)
GoParse 6.66ms × (0.97,1.04) 6.37ms × (0.97,1.04) -4.41% (p=0.000)
RegexpMatchEasy0_32 159ns × (0.99,1.00) 152ns × (0.99,1.01) -4.69% (p=0.000)
RegexpMatchEasy0_1K 538ns × (1.00,1.01) 530ns × (1.00,1.00) -1.57% (p=0.000)
RegexpMatchEasy1_32 138ns × (1.00,1.00) 134ns × (0.99,1.01) -2.91% (p=0.000)
RegexpMatchEasy1_1K 869ns × (0.99,1.01) 865ns × (1.00,1.00) -0.51% (p=0.012)
RegexpMatchMedium_32 252ns × (0.99,1.01) 233ns × (1.00,1.00) -7.85% (p=0.000)
RegexpMatchMedium_1K 72.7µs × (1.00,1.00) 69.5µs × (1.00,1.00) -4.43% (p=0.000)
RegexpMatchHard_32 3.85µs × (1.00,1.00) 3.74µs × (1.00,1.00) -2.74% (p=0.000)
RegexpMatchHard_1K 118µs × (1.00,1.00) 115µs × (1.00,1.00) -2.24% (p=0.000)
Revcomp 920ms × (0.97,1.07) 920ms × (0.97,1.04) ~ (p=0.998)
Template 129ms × (0.98,1.03) 117ms × (0.99,1.01) -9.79% (p=0.000)
TimeParse 619ns × (0.99,1.01) 615ns × (0.99,1.00) -0.57% (p=0.011)
TimeFormat 661ns × (0.98,1.04) 654ns × (0.99,1.00) ~ (p=0.223)
Change-Id: If054d81ab2c71d8d62cf54b5b1fac2af66b387fc
Reviewed-on: https://go-review.googlesource.com/9813
Reviewed-by: David Chase <drchase@google.com>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2015-05-06 12:35:53 -04:00
case ODOT , OLEN , OCAP :
2015-02-23 16:07:24 -05:00
l := safeexpr ( n . Left , init )
2015-02-13 14:40:36 -05:00
if l == n . Left {
return n
}
2015-02-23 16:07:24 -05:00
r := Nod ( OXXX , nil , nil )
2015-02-13 14:40:36 -05:00
* r = * n
r . Left = l
typecheck ( & r , Erv )
walkexpr ( & r , init )
return r
2015-04-01 09:38:44 -07:00
case ODOTPTR , OIND :
2015-02-23 16:07:24 -05:00
l := safeexpr ( n . Left , init )
2015-02-13 14:40:36 -05:00
if l == n . Left {
return n
}
2015-02-23 16:07:24 -05:00
a := Nod ( OXXX , nil , nil )
2015-02-13 14:40:36 -05:00
* a = * n
a . Left = l
walkexpr ( & a , init )
return a
2015-04-01 09:38:44 -07:00
case OINDEX , OINDEXMAP :
2015-02-23 16:07:24 -05:00
l := safeexpr ( n . Left , init )
r := safeexpr ( n . Right , init )
2015-02-13 14:40:36 -05:00
if l == n . Left && r == n . Right {
return n
}
2015-02-23 16:07:24 -05:00
a := Nod ( OXXX , nil , nil )
2015-02-13 14:40:36 -05:00
* a = * n
a . Left = l
a . Right = r
walkexpr ( & a , init )
return a
}
// make a copy; must not be used as an lvalue
2015-02-17 22:13:49 -05:00
if islvalue ( n ) {
2015-08-30 23:10:03 +02:00
Fatalf ( "missing lvalue case in safeexpr: %v" , n )
2015-02-13 14:40:36 -05:00
}
return cheapexpr ( n , init )
}
func copyexpr ( n * Node , t * Type , init * * NodeList ) * Node {
2015-02-23 16:07:24 -05:00
l := temp ( t )
a := Nod ( OAS , l , n )
2015-02-13 14:40:36 -05:00
typecheck ( & a , Etop )
walkexpr ( & a , init )
* init = list ( * init , a )
return l
}
2015-10-22 09:51:12 +09:00
// return side-effect free and cheap n, appending side effects to init.
// result may not be assignable.
2015-02-13 14:40:36 -05:00
func cheapexpr ( n * Node , init * * NodeList ) * Node {
switch n . Op {
2015-04-01 09:38:44 -07:00
case ONAME , OLITERAL :
2015-02-13 14:40:36 -05:00
return n
}
return copyexpr ( n , n . Type , init )
}
func Setmaxarg ( t * Type , extra int32 ) {
dowidth ( t )
2015-02-23 16:07:24 -05:00
w := t . Argwid
2015-02-13 14:40:36 -05:00
if w >= Thearch . MAXWIDTH {
2015-08-30 23:10:03 +02:00
Fatalf ( "bad argwid %v" , t )
2015-02-13 14:40:36 -05:00
}
w += int64 ( extra )
if w >= Thearch . MAXWIDTH {
2015-08-30 23:10:03 +02:00
Fatalf ( "bad argwid %d + %v" , extra , t )
2015-02-13 14:40:36 -05:00
}
if w > Maxarg {
Maxarg = w
}
}
2015-10-22 09:51:12 +09:00
// unicode-aware case-insensitive strcmp
2015-02-13 14:40:36 -05:00
2015-10-22 09:51:12 +09:00
// code to resolve elided DOTs
// in embedded types
2015-02-13 14:40:36 -05:00
// search depth 0 --
// return count of fields+methods
// found with a given name
func lookdot0 ( s * Sym , t * Type , save * * Type , ignorecase int ) int {
2015-02-23 16:07:24 -05:00
u := t
2015-03-01 07:54:01 +00:00
if Isptr [ u . Etype ] {
2015-02-13 14:40:36 -05:00
u = u . Type
}
2015-02-23 16:07:24 -05:00
c := 0
2015-02-13 14:40:36 -05:00
if u . Etype == TSTRUCT || u . Etype == TINTER {
2015-02-23 16:07:24 -05:00
for f := u . Type ; f != nil ; f = f . Down {
2015-02-13 14:40:36 -05:00
if f . Sym == s || ( ignorecase != 0 && f . Type . Etype == TFUNC && f . Type . Thistuple > 0 && strings . EqualFold ( f . Sym . Name , s . Name ) ) {
if save != nil {
* save = f
}
c ++
}
}
}
u = methtype ( t , 0 )
if u != nil {
2015-02-23 16:07:24 -05:00
for f := u . Method ; f != nil ; f = f . Down {
2015-02-13 14:40:36 -05:00
if f . Embedded == 0 && ( f . Sym == s || ( ignorecase != 0 && strings . EqualFold ( f . Sym . Name , s . Name ) ) ) {
if save != nil {
* save = f
}
c ++
}
}
}
return c
}
// search depth d for field/method s --
// return count of fields+methods
// found at search depth.
// answer is in dotlist array and
// count of number of ways is returned.
func adddot1 ( s * Sym , t * Type , d int , save * * Type , ignorecase int ) int {
if t . Trecur != 0 {
return 0
}
t . Trecur = 1
2015-02-23 16:07:24 -05:00
var c int
var u * Type
var a int
2015-02-13 14:40:36 -05:00
if d == 0 {
c = lookdot0 ( s , t , save , ignorecase )
goto out
}
c = 0
u = t
2015-03-01 07:54:01 +00:00
if Isptr [ u . Etype ] {
2015-02-13 14:40:36 -05:00
u = u . Type
}
if u . Etype != TSTRUCT && u . Etype != TINTER {
goto out
}
d --
2015-02-23 16:07:24 -05:00
for f := u . Type ; f != nil ; f = f . Down {
2015-02-17 22:13:49 -05:00
if f . Embedded == 0 {
2015-02-13 14:40:36 -05:00
continue
}
if f . Sym == nil {
continue
}
a = adddot1 ( s , f . Type , d , save , ignorecase )
if a != 0 && c == 0 {
dotlist [ d ] . field = f
}
c += a
}
out :
t . Trecur = 0
return c
}
// in T.field
// find missing fields that
// will give shortest unique addressing.
// modify the tree with missing type names.
func adddot ( n * Node ) * Node {
typecheck ( & n . Left , Etype | Erv )
n . Diag |= n . Left . Diag
2015-02-23 16:07:24 -05:00
t := n . Left . Type
2015-02-13 14:40:36 -05:00
if t == nil {
2015-03-02 12:35:15 -05:00
return n
2015-02-13 14:40:36 -05:00
}
if n . Left . Op == OTYPE {
2015-03-02 12:35:15 -05:00
return n
2015-02-13 14:40:36 -05:00
}
if n . Right . Op != ONAME {
2015-03-02 12:35:15 -05:00
return n
2015-02-13 14:40:36 -05:00
}
2015-03-02 12:35:15 -05:00
s := n . Right . Sym
2015-02-13 14:40:36 -05:00
if s == nil {
2015-03-02 12:35:15 -05:00
return n
2015-02-13 14:40:36 -05:00
}
2015-03-02 12:35:15 -05:00
var c int
for d := 0 ; d < len ( dotlist ) ; d ++ {
2015-02-13 14:40:36 -05:00
c = adddot1 ( s , t , d , nil , 0 )
if c > 0 {
2015-03-02 12:35:15 -05:00
if c > 1 {
2015-04-17 12:03:22 -04:00
Yyerror ( "ambiguous selector %v" , n )
2015-03-02 12:35:15 -05:00
n . Left = nil
return n
}
2015-02-13 14:40:36 -05:00
2015-03-02 12:35:15 -05:00
// rebuild elided dots
for c := d - 1 ; c >= 0 ; c -- {
n . Left = Nod ( ODOT , n . Left , newname ( dotlist [ c ] . field . Sym ) )
2015-07-22 15:03:02 -04:00
n . Left . Implicit = true
2015-03-02 12:35:15 -05:00
}
2015-02-13 14:40:36 -05:00
2015-03-02 12:35:15 -05:00
return n
2014-12-09 07:59:24 -08:00
}
2015-02-13 14:40:36 -05:00
}
return n
}
2015-10-22 09:51:12 +09:00
// code to help generate trampoline
// functions for methods on embedded
// subtypes.
// these are approx the same as
// the corresponding adddot routines
// except that they expect to be called
// with unique tasks and they return
// the actual methods.
2015-02-13 14:40:36 -05:00
type Symlink struct {
field * Type
link * Symlink
2015-09-08 20:29:10 +02:00
good bool
followptr bool
2015-02-13 14:40:36 -05:00
}
var slist * Symlink
2015-09-08 20:29:10 +02:00
func expand0 ( t * Type , followptr bool ) {
2015-02-23 16:07:24 -05:00
u := t
2015-03-01 07:54:01 +00:00
if Isptr [ u . Etype ] {
2015-09-08 20:29:10 +02:00
followptr = true
2015-02-13 14:40:36 -05:00
u = u . Type
}
if u . Etype == TINTER {
2015-02-23 16:07:24 -05:00
var sl * Symlink
for f := u . Type ; f != nil ; f = f . Down {
2015-02-13 14:40:36 -05:00
if f . Sym . Flags & SymUniq != 0 {
continue
}
f . Sym . Flags |= SymUniq
sl = new ( Symlink )
sl . field = f
sl . link = slist
2015-09-08 20:29:10 +02:00
sl . followptr = followptr
2015-02-13 14:40:36 -05:00
slist = sl
}
return
}
u = methtype ( t , 0 )
if u != nil {
2015-02-23 16:07:24 -05:00
var sl * Symlink
for f := u . Method ; f != nil ; f = f . Down {
2015-02-13 14:40:36 -05:00
if f . Sym . Flags & SymUniq != 0 {
continue
}
f . Sym . Flags |= SymUniq
sl = new ( Symlink )
sl . field = f
sl . link = slist
2015-09-08 20:29:10 +02:00
sl . followptr = followptr
2015-02-13 14:40:36 -05:00
slist = sl
}
}
}
2015-09-08 20:29:10 +02:00
func expand1 ( t * Type , d int , followptr bool ) {
2015-02-13 14:40:36 -05:00
if t . Trecur != 0 {
return
}
if d == 0 {
return
}
t . Trecur = 1
if d != len ( dotlist ) - 1 {
expand0 ( t , followptr )
}
2015-02-23 16:07:24 -05:00
u := t
2015-03-01 07:54:01 +00:00
if Isptr [ u . Etype ] {
2015-09-08 20:29:10 +02:00
followptr = true
2015-02-13 14:40:36 -05:00
u = u . Type
}
if u . Etype != TSTRUCT && u . Etype != TINTER {
goto out
}
2015-02-23 16:07:24 -05:00
for f := u . Type ; f != nil ; f = f . Down {
2015-02-17 22:13:49 -05:00
if f . Embedded == 0 {
2015-02-13 14:40:36 -05:00
continue
}
if f . Sym == nil {
continue
}
expand1 ( f . Type , d - 1 , followptr )
}
out :
t . Trecur = 0
}
func expandmeth ( t * Type ) {
if t == nil || t . Xmethod != nil {
return
}
// mark top-level method symbols
// so that expand1 doesn't consider them.
2015-02-23 16:07:24 -05:00
var f * Type
2015-02-13 14:40:36 -05:00
for f = t . Method ; f != nil ; f = f . Down {
f . Sym . Flags |= SymUniq
}
// generate all reachable methods
slist = nil
2015-09-08 20:29:10 +02:00
expand1 ( t , len ( dotlist ) - 1 , false )
2015-02-13 14:40:36 -05:00
// check each method to be uniquely reachable
2015-02-23 16:07:24 -05:00
var c int
var d int
for sl := slist ; sl != nil ; sl = sl . link {
2015-02-13 14:40:36 -05:00
sl . field . Sym . Flags &^= SymUniq
for d = 0 ; d < len ( dotlist ) ; d ++ {
c = adddot1 ( sl . field . Sym , t , d , & f , 0 )
if c == 0 {
continue
}
if c == 1 {
// addot1 may have dug out arbitrary fields, we only want methods.
if f . Type . Etype == TFUNC && f . Type . Thistuple > 0 {
2015-09-08 20:29:10 +02:00
sl . good = true
2015-02-13 14:40:36 -05:00
sl . field = f
}
}
break
}
}
for f = t . Method ; f != nil ; f = f . Down {
f . Sym . Flags &^= SymUniq
}
t . Xmethod = t . Method
2015-02-23 16:07:24 -05:00
for sl := slist ; sl != nil ; sl = sl . link {
2015-09-08 20:29:10 +02:00
if sl . good {
2015-02-13 14:40:36 -05:00
// add it to the base type method list
f = typ ( TFIELD )
* f = * sl . field
f . Embedded = 1 // needs a trampoline
2015-09-08 20:29:10 +02:00
if sl . followptr {
2015-02-13 14:40:36 -05:00
f . Embedded = 2
}
f . Down = t . Xmethod
t . Xmethod = f
}
}
}
2015-10-22 09:51:12 +09:00
// Given funarg struct list, return list of ODCLFIELD Node fn args.
2015-02-13 14:40:36 -05:00
func structargs ( tl * * Type , mustname int ) * NodeList {
var savet Iter
var a * Node
var n * Node
var buf string
2015-03-02 14:22:05 -05:00
var args * NodeList
2015-02-23 16:07:24 -05:00
gen := 0
for t := Structfirst ( & savet , tl ) ; t != nil ; t = structnext ( & savet ) {
2015-02-13 14:40:36 -05:00
n = nil
if mustname != 0 && ( t . Sym == nil || t . Sym . Name == "_" ) {
// invent a name so that we can refer to it in the trampoline
buf = fmt . Sprintf ( ".anon%d" , gen )
gen ++
n = newname ( Lookup ( buf ) )
} else if t . Sym != nil {
n = newname ( t . Sym )
}
a = Nod ( ODCLFIELD , n , typenod ( t . Type ) )
a . Isddd = t . Isddd
if n != nil {
n . Isddd = t . Isddd
}
args = list ( args , a )
}
return args
}
2015-10-22 09:51:12 +09:00
// Generate a wrapper function to convert from
// a receiver of type T to a receiver of type U.
// That is,
//
// func (t T) M() {
// ...
// }
//
// already exists; this function generates
//
// func (u U) M() {
// u.M()
// }
//
// where the types T and U are such that u.M() is valid
// and calls the T.M method.
// The resulting function is for use in method tables.
//
// rcvr - U
// method - M func (t T)(), a TFIELD type struct
// newnam - the eventual mangled name of this function
2015-02-13 14:40:36 -05:00
var genwrapper_linehistdone int = 0
func genwrapper ( rcvr * Type , method * Type , newnam * Sym , iface int ) {
if false && Debug [ 'r' ] != 0 {
2015-04-17 12:03:22 -04:00
fmt . Printf ( "genwrapper rcvrtype=%v method=%v newnam=%v\n" , rcvr , method , newnam )
2015-02-13 14:40:36 -05:00
}
lexlineno ++
lineno = lexlineno
if genwrapper_linehistdone == 0 {
// All the wrappers can share the same linehist entry.
2015-04-20 13:32:40 -07:00
linehistpush ( "<autogenerated>" )
2015-02-13 14:40:36 -05:00
genwrapper_linehistdone = 1
}
dclcontext = PEXTERN
markdcl ( )
2015-02-23 16:07:24 -05:00
this := Nod ( ODCLFIELD , newname ( Lookup ( ".this" ) ) , typenod ( rcvr ) )
2015-05-27 00:44:05 -04:00
this . Left . Name . Param . Ntype = this . Right
2015-02-23 16:07:24 -05:00
in := structargs ( getinarg ( method . Type ) , 1 )
out := structargs ( Getoutarg ( method . Type ) , 0 )
2015-02-13 14:40:36 -05:00
2015-02-23 16:07:24 -05:00
t := Nod ( OTFUNC , nil , nil )
l := list1 ( this )
2015-02-13 14:40:36 -05:00
if iface != 0 && rcvr . Width < Types [ Tptr ] . Width {
// Building method for interface table and receiver
// is smaller than the single pointer-sized word
// that the interface call will pass in.
// Add a dummy padding argument after the
// receiver to make up the difference.
2015-02-23 16:07:24 -05:00
tpad := typ ( TARRAY )
2015-02-13 14:40:36 -05:00
tpad . Type = Types [ TUINT8 ]
tpad . Bound = Types [ Tptr ] . Width - rcvr . Width
2015-02-23 16:07:24 -05:00
pad := Nod ( ODCLFIELD , newname ( Lookup ( ".pad" ) ) , typenod ( tpad ) )
2015-02-13 14:40:36 -05:00
l = list ( l , pad )
}
t . List = concat ( l , in )
t . Rlist = out
2015-02-23 16:07:24 -05:00
fn := Nod ( ODCLFUNC , nil , nil )
2015-05-27 10:42:55 -04:00
fn . Func . Nname = newname ( newnam )
fn . Func . Nname . Name . Defn = fn
fn . Func . Nname . Name . Param . Ntype = t
declare ( fn . Func . Nname , PFUNC )
2015-02-13 14:40:36 -05:00
funchdr ( fn )
// arg list
2015-03-02 14:22:05 -05:00
var args * NodeList
2015-02-13 14:40:36 -05:00
2015-03-09 16:24:07 +11:00
isddd := false
2015-02-23 16:07:24 -05:00
for l := in ; l != nil ; l = l . Next {
2015-02-13 14:40:36 -05:00
args = list ( args , l . N . Left )
2015-03-09 16:24:07 +11:00
isddd = l . N . Left . Isddd
2015-02-13 14:40:36 -05:00
}
2015-02-23 16:07:24 -05:00
methodrcvr := getthisx ( method . Type ) . Type . Type
2015-02-13 14:40:36 -05:00
// generate nil pointer check for better error
2015-03-01 07:54:01 +00:00
if Isptr [ rcvr . Etype ] && rcvr . Type == methodrcvr {
2015-02-13 14:40:36 -05:00
// generating wrapper from *T to T.
2015-02-23 16:07:24 -05:00
n := Nod ( OIF , nil , nil )
2015-02-13 14:40:36 -05:00
2015-05-26 21:30:20 -04:00
n . Left = Nod ( OEQ , this . Left , nodnil ( ) )
2015-02-13 14:40:36 -05:00
// these strings are already in the reflect tables,
// so no space cost to use them here.
2015-03-02 14:22:05 -05:00
var l * NodeList
2015-02-13 14:40:36 -05:00
2015-02-23 16:07:24 -05:00
var v Val
2015-05-14 17:57:42 -07:00
v . U = rcvr . Type . Sym . Pkg . Name // package name
2015-02-13 14:40:36 -05:00
l = list ( l , nodlit ( v ) )
2015-05-14 17:57:42 -07:00
v . U = rcvr . Type . Sym . Name // type name
2015-02-13 14:40:36 -05:00
l = list ( l , nodlit ( v ) )
2015-05-14 17:57:42 -07:00
v . U = method . Sym . Name
2015-02-13 14:40:36 -05:00
l = list ( l , nodlit ( v ) ) // method name
2015-02-23 16:07:24 -05:00
call := Nod ( OCALL , syslook ( "panicwrap" , 0 ) , nil )
2015-02-13 14:40:36 -05:00
call . List = l
n . Nbody = list1 ( call )
fn . Nbody = list ( fn . Nbody , n )
}
2015-02-23 16:07:24 -05:00
dot := adddot ( Nod ( OXDOT , this . Left , newname ( method . Sym ) ) )
2015-02-13 14:40:36 -05:00
// generate call
2015-10-20 10:00:07 -07:00
if ! instrumenting && Isptr [ rcvr . Etype ] && Isptr [ methodrcvr . Etype ] && method . Embedded != 0 && ! isifacemethod ( method . Type ) {
2015-02-13 14:40:36 -05:00
// generate tail call: adjust pointer receiver and jump to embedded method.
dot = dot . Left // skip final .M
2015-03-01 07:54:01 +00:00
if ! Isptr [ dotlist [ 0 ] . field . Type . Etype ] {
2015-02-13 14:40:36 -05:00
dot = Nod ( OADDR , dot , nil )
}
2015-02-23 16:07:24 -05:00
as := Nod ( OAS , this . Left , Nod ( OCONVNOP , dot , nil ) )
2015-02-13 14:40:36 -05:00
as . Right . Type = rcvr
fn . Nbody = list ( fn . Nbody , as )
2015-02-23 16:07:24 -05:00
n := Nod ( ORETJMP , nil , nil )
2015-02-13 14:40:36 -05:00
n . Left = newname ( methodsym ( method . Sym , methodrcvr , 0 ) )
fn . Nbody = list ( fn . Nbody , n )
} else {
2015-03-25 19:33:01 -07:00
fn . Func . Wrapper = true // ignore frame for panic+recover matching
2015-02-23 16:07:24 -05:00
call := Nod ( OCALL , dot , nil )
2015-02-13 14:40:36 -05:00
call . List = args
2015-03-09 16:24:07 +11:00
call . Isddd = isddd
2015-02-13 14:40:36 -05:00
if method . Type . Outtuple > 0 {
2015-02-23 16:07:24 -05:00
n := Nod ( ORETURN , nil , nil )
2015-02-13 14:40:36 -05:00
n . List = list1 ( call )
call = n
}
fn . Nbody = list ( fn . Nbody , call )
}
if false && Debug [ 'r' ] != 0 {
dumplist ( "genwrapper body" , fn . Nbody )
}
funcbody ( fn )
Curfn = fn
// wrappers where T is anonymous (struct or interface) can be duplicated.
2015-03-01 07:54:01 +00:00
if rcvr . Etype == TSTRUCT || rcvr . Etype == TINTER || Isptr [ rcvr . Etype ] && rcvr . Type . Etype == TSTRUCT {
2015-03-25 19:33:01 -07:00
fn . Func . Dupok = true
2015-02-13 14:40:36 -05:00
}
typecheck ( & fn , Etop )
typechecklist ( fn . Nbody , Etop )
inlcalls ( fn )
2015-09-05 12:30:13 +10:00
escAnalyze ( [ ] * Node { fn } , false )
2015-02-13 14:40:36 -05:00
Curfn = nil
funccompile ( fn )
}
func hashmem ( t * Type ) * Node {
2015-02-23 16:07:24 -05:00
sym := Pkglookup ( "memhash" , Runtimepkg )
2015-02-13 14:40:36 -05:00
2015-02-23 16:07:24 -05:00
n := newname ( sym )
2015-02-13 14:40:36 -05:00
n . Class = PFUNC
2015-02-23 16:07:24 -05:00
tfn := Nod ( OTFUNC , nil , nil )
2015-02-13 14:40:36 -05:00
tfn . List = list ( tfn . List , Nod ( ODCLFIELD , nil , typenod ( Ptrto ( t ) ) ) )
tfn . List = list ( tfn . List , Nod ( ODCLFIELD , nil , typenod ( Types [ TUINTPTR ] ) ) )
tfn . List = list ( tfn . List , Nod ( ODCLFIELD , nil , typenod ( Types [ TUINTPTR ] ) ) )
tfn . Rlist = list ( tfn . Rlist , Nod ( ODCLFIELD , nil , typenod ( Types [ TUINTPTR ] ) ) )
typecheck ( & tfn , Etype )
n . Type = tfn . Type
return n
}
func hashfor ( t * Type ) * Node {
var sym * Sym
2015-02-23 16:07:24 -05:00
a := algtype1 ( t , nil )
2015-02-13 14:40:36 -05:00
switch a {
case AMEM :
2015-08-30 23:10:03 +02:00
Fatalf ( "hashfor with AMEM type" )
2015-02-13 14:40:36 -05:00
case AINTER :
sym = Pkglookup ( "interhash" , Runtimepkg )
case ANILINTER :
sym = Pkglookup ( "nilinterhash" , Runtimepkg )
case ASTRING :
sym = Pkglookup ( "strhash" , Runtimepkg )
case AFLOAT32 :
sym = Pkglookup ( "f32hash" , Runtimepkg )
case AFLOAT64 :
sym = Pkglookup ( "f64hash" , Runtimepkg )
case ACPLX64 :
sym = Pkglookup ( "c64hash" , Runtimepkg )
case ACPLX128 :
sym = Pkglookup ( "c128hash" , Runtimepkg )
default :
sym = typesymprefix ( ".hash" , t )
}
2015-02-23 16:07:24 -05:00
n := newname ( sym )
2015-02-13 14:40:36 -05:00
n . Class = PFUNC
2015-02-23 16:07:24 -05:00
tfn := Nod ( OTFUNC , nil , nil )
2015-02-13 14:40:36 -05:00
tfn . List = list ( tfn . List , Nod ( ODCLFIELD , nil , typenod ( Ptrto ( t ) ) ) )
tfn . List = list ( tfn . List , Nod ( ODCLFIELD , nil , typenod ( Types [ TUINTPTR ] ) ) )
tfn . Rlist = list ( tfn . Rlist , Nod ( ODCLFIELD , nil , typenod ( Types [ TUINTPTR ] ) ) )
typecheck ( & tfn , Etype )
n . Type = tfn . Type
return n
}
2015-10-22 09:51:12 +09:00
// Generate a helper function to compute the hash of a value of type t.
2015-02-13 14:40:36 -05:00
func genhash ( sym * Sym , t * Type ) {
if Debug [ 'r' ] != 0 {
2015-04-17 12:03:22 -04:00
fmt . Printf ( "genhash %v %v\n" , sym , t )
2015-02-13 14:40:36 -05:00
}
lineno = 1 // less confusing than end of input
dclcontext = PEXTERN
markdcl ( )
// func sym(p *T, h uintptr) uintptr
2015-02-23 16:07:24 -05:00
fn := Nod ( ODCLFUNC , nil , nil )
2015-02-13 14:40:36 -05:00
2015-05-27 10:42:55 -04:00
fn . Func . Nname = newname ( sym )
fn . Func . Nname . Class = PFUNC
2015-02-23 16:07:24 -05:00
tfn := Nod ( OTFUNC , nil , nil )
2015-05-27 10:42:55 -04:00
fn . Func . Nname . Name . Param . Ntype = tfn
2015-02-13 14:40:36 -05:00
2015-02-23 16:07:24 -05:00
n := Nod ( ODCLFIELD , newname ( Lookup ( "p" ) ) , typenod ( Ptrto ( t ) ) )
2015-02-13 14:40:36 -05:00
tfn . List = list ( tfn . List , n )
2015-02-23 16:07:24 -05:00
np := n . Left
2015-02-13 14:40:36 -05:00
n = Nod ( ODCLFIELD , newname ( Lookup ( "h" ) ) , typenod ( Types [ TUINTPTR ] ) )
tfn . List = list ( tfn . List , n )
2015-02-23 16:07:24 -05:00
nh := n . Left
2015-02-13 14:40:36 -05:00
n = Nod ( ODCLFIELD , nil , typenod ( Types [ TUINTPTR ] ) ) // return value
tfn . Rlist = list ( tfn . Rlist , n )
funchdr ( fn )
2015-05-27 10:42:55 -04:00
typecheck ( & fn . Func . Nname . Name . Param . Ntype , Etype )
2015-02-13 14:40:36 -05:00
// genhash is only called for types that have equality but
// cannot be handled by the standard algorithms,
// so t must be either an array or a struct.
switch t . Etype {
default :
2015-08-30 23:10:03 +02:00
Fatalf ( "genhash %v" , t )
2015-02-13 14:40:36 -05:00
case TARRAY :
2015-02-17 22:13:49 -05:00
if Isslice ( t ) {
2015-08-30 23:10:03 +02:00
Fatalf ( "genhash %v" , t )
2015-02-13 14:40:36 -05:00
}
// An array of pure memory would be handled by the
// standard algorithm, so the element type must not be
// pure memory.
2015-02-23 16:07:24 -05:00
hashel := hashfor ( t . Type )
2015-02-13 14:40:36 -05:00
2015-02-23 16:07:24 -05:00
n := Nod ( ORANGE , nil , Nod ( OIND , np , nil ) )
ni := newname ( Lookup ( "i" ) )
2015-02-13 14:40:36 -05:00
ni . Type = Types [ TINT ]
n . List = list1 ( ni )
2015-04-02 19:58:37 -07:00
n . Colas = true
2015-02-13 14:40:36 -05:00
colasdefn ( n . List , n )
ni = n . List . N
// h = hashel(&p[i], h)
2015-02-23 16:07:24 -05:00
call := Nod ( OCALL , hashel , nil )
2015-02-13 14:40:36 -05:00
2015-02-23 16:07:24 -05:00
nx := Nod ( OINDEX , np , ni )
2015-02-17 22:13:49 -05:00
nx . Bounded = true
2015-02-23 16:07:24 -05:00
na := Nod ( OADDR , nx , nil )
2015-02-13 14:40:36 -05:00
na . Etype = 1 // no escape to heap
call . List = list ( call . List , na )
call . List = list ( call . List , nh )
n . Nbody = list ( n . Nbody , Nod ( OAS , nh , call ) )
fn . Nbody = list ( fn . Nbody , n )
// Walk the struct using memhash for runs of AMEM
// and calling specific hash functions for the others.
case TSTRUCT :
2015-03-02 14:22:05 -05:00
var first * Type
2015-02-23 16:07:24 -05:00
offend := int64 ( 0 )
var size int64
var call * Node
var nx * Node
var na * Node
var hashel * Node
for t1 := t . Type ; ; t1 = t1 . Down {
2015-02-13 14:40:36 -05:00
if t1 != nil && algtype1 ( t1 . Type , nil ) == AMEM && ! isblanksym ( t1 . Sym ) {
offend = t1 . Width + t1 . Type . Width
if first == nil {
first = t1
}
// If it's a memory field but it's padded, stop here.
2015-02-17 22:13:49 -05:00
if ispaddedfield ( t1 , t . Width ) {
2015-02-13 14:40:36 -05:00
t1 = t1 . Down
} else {
continue
}
}
// Run memhash for fields up to this one.
if first != nil {
size = offend - first . Width // first->width is offset
hashel = hashmem ( first . Type )
// h = hashel(&p.first, size, h)
call = Nod ( OCALL , hashel , nil )
nx = Nod ( OXDOT , np , newname ( first . Sym ) ) // TODO: fields from other packages?
na = Nod ( OADDR , nx , nil )
na . Etype = 1 // no escape to heap
call . List = list ( call . List , na )
call . List = list ( call . List , nh )
call . List = list ( call . List , Nodintconst ( size ) )
fn . Nbody = list ( fn . Nbody , Nod ( OAS , nh , call ) )
first = nil
}
if t1 == nil {
break
}
if isblanksym ( t1 . Sym ) {
continue
}
// Run hash for this field.
if algtype1 ( t1 . Type , nil ) == AMEM {
hashel = hashmem ( t1 . Type )
// h = memhash(&p.t1, h, size)
call = Nod ( OCALL , hashel , nil )
nx = Nod ( OXDOT , np , newname ( t1 . Sym ) ) // TODO: fields from other packages?
na = Nod ( OADDR , nx , nil )
na . Etype = 1 // no escape to heap
call . List = list ( call . List , na )
call . List = list ( call . List , nh )
call . List = list ( call . List , Nodintconst ( t1 . Type . Width ) )
fn . Nbody = list ( fn . Nbody , Nod ( OAS , nh , call ) )
} else {
hashel = hashfor ( t1 . Type )
// h = hashel(&p.t1, h)
call = Nod ( OCALL , hashel , nil )
nx = Nod ( OXDOT , np , newname ( t1 . Sym ) ) // TODO: fields from other packages?
na = Nod ( OADDR , nx , nil )
na . Etype = 1 // no escape to heap
call . List = list ( call . List , na )
call . List = list ( call . List , nh )
fn . Nbody = list ( fn . Nbody , Nod ( OAS , nh , call ) )
}
}
}
2015-02-23 16:07:24 -05:00
r := Nod ( ORETURN , nil , nil )
2015-02-13 14:40:36 -05:00
r . List = list ( r . List , nh )
fn . Nbody = list ( fn . Nbody , r )
if Debug [ 'r' ] != 0 {
dumplist ( "genhash body" , fn . Nbody )
}
funcbody ( fn )
Curfn = fn
2015-03-25 19:33:01 -07:00
fn . Func . Dupok = true
2015-02-13 14:40:36 -05:00
typecheck ( & fn , Etop )
typechecklist ( fn . Nbody , Etop )
Curfn = nil
// Disable safemode while compiling this code: the code we
// generate internally can refer to unsafe.Pointer.
// In this case it can happen if we need to generate an ==
// for a struct containing a reflect.Value, which itself has
// an unexported field of type unsafe.Pointer.
2015-02-23 16:07:24 -05:00
old_safemode := safemode
2015-02-13 14:40:36 -05:00
safemode = 0
funccompile ( fn )
safemode = old_safemode
}
2015-05-04 16:12:52 -07:00
// eqfield returns the node
// p.field == q.field
2015-02-13 14:40:36 -05:00
func eqfield ( p * Node , q * Node , field * Node ) * Node {
2015-02-23 16:07:24 -05:00
nx := Nod ( OXDOT , p , field )
ny := Nod ( OXDOT , q , field )
2015-05-04 16:12:52 -07:00
ne := Nod ( OEQ , nx , ny )
return ne
2015-02-13 14:40:36 -05:00
}
func eqmemfunc ( size int64 , type_ * Type , needsize * int ) * Node {
var fn * Node
switch size {
default :
fn = syslook ( "memequal" , 1 )
* needsize = 1
2015-03-08 13:33:49 -04:00
case 1 , 2 , 4 , 8 , 16 :
2015-02-23 16:07:24 -05:00
buf := fmt . Sprintf ( "memequal%d" , int ( size ) * 8 )
2015-02-13 14:40:36 -05:00
fn = syslook ( buf , 1 )
* needsize = 0
}
2015-03-08 13:33:49 -04:00
substArgTypes ( fn , type_ , type_ )
2015-02-13 14:40:36 -05:00
return fn
}
2015-05-04 16:12:52 -07:00
// eqmem returns the node
// memequal(&p.field, &q.field [, size])
2015-02-13 14:40:36 -05:00
func eqmem ( p * Node , q * Node , field * Node , size int64 ) * Node {
var needsize int
2015-02-23 16:07:24 -05:00
nx := Nod ( OADDR , Nod ( OXDOT , p , field ) , nil )
2015-02-13 14:40:36 -05:00
nx . Etype = 1 // does not escape
2015-02-23 16:07:24 -05:00
ny := Nod ( OADDR , Nod ( OXDOT , q , field ) , nil )
2015-02-13 14:40:36 -05:00
ny . Etype = 1 // does not escape
typecheck ( & nx , Erv )
typecheck ( & ny , Erv )
2015-02-23 16:07:24 -05:00
call := Nod ( OCALL , eqmemfunc ( size , nx . Type . Type , & needsize ) , nil )
2015-02-13 14:40:36 -05:00
call . List = list ( call . List , nx )
call . List = list ( call . List , ny )
if needsize != 0 {
call . List = list ( call . List , Nodintconst ( size ) )
}
2015-05-04 16:12:52 -07:00
return call
2015-02-13 14:40:36 -05:00
}
2015-05-04 16:12:52 -07:00
// geneq generates a helper function to
// check equality of two values of type t.
2015-02-13 14:40:36 -05:00
func geneq ( sym * Sym , t * Type ) {
if Debug [ 'r' ] != 0 {
2015-04-17 12:03:22 -04:00
fmt . Printf ( "geneq %v %v\n" , sym , t )
2015-02-13 14:40:36 -05:00
}
lineno = 1 // less confusing than end of input
dclcontext = PEXTERN
markdcl ( )
// func sym(p, q *T) bool
2015-02-23 16:07:24 -05:00
fn := Nod ( ODCLFUNC , nil , nil )
2015-02-13 14:40:36 -05:00
2015-05-27 10:42:55 -04:00
fn . Func . Nname = newname ( sym )
fn . Func . Nname . Class = PFUNC
2015-02-23 16:07:24 -05:00
tfn := Nod ( OTFUNC , nil , nil )
2015-05-27 10:42:55 -04:00
fn . Func . Nname . Name . Param . Ntype = tfn
2015-02-13 14:40:36 -05:00
2015-02-23 16:07:24 -05:00
n := Nod ( ODCLFIELD , newname ( Lookup ( "p" ) ) , typenod ( Ptrto ( t ) ) )
2015-02-13 14:40:36 -05:00
tfn . List = list ( tfn . List , n )
2015-02-23 16:07:24 -05:00
np := n . Left
2015-02-13 14:40:36 -05:00
n = Nod ( ODCLFIELD , newname ( Lookup ( "q" ) ) , typenod ( Ptrto ( t ) ) )
tfn . List = list ( tfn . List , n )
2015-02-23 16:07:24 -05:00
nq := n . Left
2015-02-13 14:40:36 -05:00
n = Nod ( ODCLFIELD , nil , typenod ( Types [ TBOOL ] ) )
tfn . Rlist = list ( tfn . Rlist , n )
funchdr ( fn )
// geneq is only called for types that have equality but
// cannot be handled by the standard algorithms,
// so t must be either an array or a struct.
switch t . Etype {
default :
2015-08-30 23:10:03 +02:00
Fatalf ( "geneq %v" , t )
2015-02-13 14:40:36 -05:00
case TARRAY :
2015-02-17 22:13:49 -05:00
if Isslice ( t ) {
2015-08-30 23:10:03 +02:00
Fatalf ( "geneq %v" , t )
2015-02-13 14:40:36 -05:00
}
// An array of pure memory would be handled by the
// standard memequal, so the element type must not be
// pure memory. Even if we unrolled the range loop,
// each iteration would be a function call, so don't bother
// unrolling.
2015-02-23 16:07:24 -05:00
nrange := Nod ( ORANGE , nil , Nod ( OIND , np , nil ) )
2015-02-13 14:40:36 -05:00
2015-02-23 16:07:24 -05:00
ni := newname ( Lookup ( "i" ) )
2015-02-13 14:40:36 -05:00
ni . Type = Types [ TINT ]
nrange . List = list1 ( ni )
2015-04-02 19:58:37 -07:00
nrange . Colas = true
2015-02-13 14:40:36 -05:00
colasdefn ( nrange . List , nrange )
ni = nrange . List . N
// if p[i] != q[i] { return false }
2015-02-23 16:07:24 -05:00
nx := Nod ( OINDEX , np , ni )
2015-02-13 14:40:36 -05:00
2015-02-17 22:13:49 -05:00
nx . Bounded = true
2015-02-23 16:07:24 -05:00
ny := Nod ( OINDEX , nq , ni )
2015-02-17 22:13:49 -05:00
ny . Bounded = true
2015-02-13 14:40:36 -05:00
2015-02-23 16:07:24 -05:00
nif := Nod ( OIF , nil , nil )
2015-05-26 21:30:20 -04:00
nif . Left = Nod ( ONE , nx , ny )
2015-02-23 16:07:24 -05:00
r := Nod ( ORETURN , nil , nil )
2015-02-17 22:13:49 -05:00
r . List = list ( r . List , Nodbool ( false ) )
2015-02-13 14:40:36 -05:00
nif . Nbody = list ( nif . Nbody , r )
nrange . Nbody = list ( nrange . Nbody , nif )
fn . Nbody = list ( fn . Nbody , nrange )
2015-05-04 16:12:52 -07:00
// return true
ret := Nod ( ORETURN , nil , nil )
ret . List = list ( ret . List , Nodbool ( true ) )
fn . Nbody = list ( fn . Nbody , ret )
// Walk the struct using memequal for runs of AMEM
2015-02-13 14:40:36 -05:00
// and calling specific equality tests for the others.
// Skip blank-named fields.
case TSTRUCT :
2015-03-02 14:22:05 -05:00
var first * Type
2015-02-13 14:40:36 -05:00
2015-05-04 16:12:52 -07:00
var conjuncts [ ] * Node
2015-02-23 16:07:24 -05:00
offend := int64 ( 0 )
var size int64
for t1 := t . Type ; ; t1 = t1 . Down {
2015-02-13 14:40:36 -05:00
if t1 != nil && algtype1 ( t1 . Type , nil ) == AMEM && ! isblanksym ( t1 . Sym ) {
offend = t1 . Width + t1 . Type . Width
if first == nil {
first = t1
}
// If it's a memory field but it's padded, stop here.
2015-02-17 22:13:49 -05:00
if ispaddedfield ( t1 , t . Width ) {
2015-02-13 14:40:36 -05:00
t1 = t1 . Down
} else {
continue
}
}
// Run memequal for fields up to this one.
// TODO(rsc): All the calls to newname are wrong for
// cross-package unexported fields.
if first != nil {
if first . Down == t1 {
2015-05-04 16:12:52 -07:00
conjuncts = append ( conjuncts , eqfield ( np , nq , newname ( first . Sym ) ) )
2015-02-13 14:40:36 -05:00
} else if first . Down . Down == t1 {
2015-05-04 16:12:52 -07:00
conjuncts = append ( conjuncts , eqfield ( np , nq , newname ( first . Sym ) ) )
2015-02-13 14:40:36 -05:00
first = first . Down
if ! isblanksym ( first . Sym ) {
2015-05-04 16:12:52 -07:00
conjuncts = append ( conjuncts , eqfield ( np , nq , newname ( first . Sym ) ) )
2015-02-13 14:40:36 -05:00
}
} else {
// More than two fields: use memequal.
size = offend - first . Width // first->width is offset
2015-05-04 16:12:52 -07:00
conjuncts = append ( conjuncts , eqmem ( np , nq , newname ( first . Sym ) , size ) )
2015-02-13 14:40:36 -05:00
}
first = nil
}
if t1 == nil {
break
}
if isblanksym ( t1 . Sym ) {
continue
}
// Check this field, which is not just memory.
2015-05-04 16:12:52 -07:00
conjuncts = append ( conjuncts , eqfield ( np , nq , newname ( t1 . Sym ) ) )
2015-02-13 14:40:36 -05:00
}
2015-05-04 16:12:52 -07:00
var and * Node
switch len ( conjuncts ) {
case 0 :
and = Nodbool ( true )
case 1 :
and = conjuncts [ 0 ]
default :
and = Nod ( OANDAND , conjuncts [ 0 ] , conjuncts [ 1 ] )
for _ , conjunct := range conjuncts [ 2 : ] {
and = Nod ( OANDAND , and , conjunct )
}
}
2015-02-13 14:40:36 -05:00
2015-05-04 16:12:52 -07:00
ret := Nod ( ORETURN , nil , nil )
ret . List = list ( ret . List , and )
fn . Nbody = list ( fn . Nbody , ret )
}
2015-02-13 14:40:36 -05:00
if Debug [ 'r' ] != 0 {
dumplist ( "geneq body" , fn . Nbody )
}
funcbody ( fn )
Curfn = fn
2015-03-25 19:33:01 -07:00
fn . Func . Dupok = true
2015-02-13 14:40:36 -05:00
typecheck ( & fn , Etop )
typechecklist ( fn . Nbody , Etop )
Curfn = nil
// Disable safemode while compiling this code: the code we
// generate internally can refer to unsafe.Pointer.
// In this case it can happen if we need to generate an ==
// for a struct containing a reflect.Value, which itself has
// an unexported field of type unsafe.Pointer.
2015-02-23 16:07:24 -05:00
old_safemode := safemode
2015-02-13 14:40:36 -05:00
safemode = 0
2015-05-04 18:16:50 -07:00
// Disable checknils while compiling this code.
// We are comparing a struct or an array,
// neither of which can be nil, and our comparisons
// are shallow.
Disable_checknil ++
2015-02-13 14:40:36 -05:00
funccompile ( fn )
2015-05-04 18:16:50 -07:00
2015-02-13 14:40:36 -05:00
safemode = old_safemode
2015-05-04 18:16:50 -07:00
Disable_checknil --
2015-02-13 14:40:36 -05:00
}
2015-09-08 20:29:10 +02:00
func ifacelookdot ( s * Sym , t * Type , followptr * bool , ignorecase int ) * Type {
* followptr = false
2015-02-13 14:40:36 -05:00
if t == nil {
return nil
}
2015-02-23 16:07:24 -05:00
var m * Type
var i int
var c int
for d := 0 ; d < len ( dotlist ) ; d ++ {
2015-02-13 14:40:36 -05:00
c = adddot1 ( s , t , d , & m , ignorecase )
if c > 1 {
2015-04-17 12:03:22 -04:00
Yyerror ( "%v.%v is ambiguous" , t , s )
2015-02-13 14:40:36 -05:00
return nil
}
if c == 1 {
for i = 0 ; i < d ; i ++ {
2015-03-01 07:54:01 +00:00
if Isptr [ dotlist [ i ] . field . Type . Etype ] {
2015-09-08 20:29:10 +02:00
* followptr = true
2015-02-13 14:40:36 -05:00
break
}
}
if m . Type . Etype != TFUNC || m . Type . Thistuple == 0 {
2015-04-17 12:03:22 -04:00
Yyerror ( "%v.%v is a field, not a method" , t , s )
2015-02-13 14:40:36 -05:00
return nil
}
return m
}
}
return nil
}
2015-02-17 22:13:49 -05:00
func implements ( t * Type , iface * Type , m * * Type , samename * * Type , ptr * int ) bool {
2015-02-23 16:07:24 -05:00
t0 := t
2015-02-13 14:40:36 -05:00
if t == nil {
2015-02-17 22:13:49 -05:00
return false
2015-02-13 14:40:36 -05:00
}
// if this is too slow,
// could sort these first
// and then do one loop.
if t . Etype == TINTER {
2015-02-23 16:07:24 -05:00
var tm * Type
for im := iface . Type ; im != nil ; im = im . Down {
2015-02-13 14:40:36 -05:00
for tm = t . Type ; tm != nil ; tm = tm . Down {
if tm . Sym == im . Sym {
if Eqtype ( tm . Type , im . Type ) {
goto found
}
* m = im
* samename = tm
* ptr = 0
2015-02-17 22:13:49 -05:00
return false
2015-02-13 14:40:36 -05:00
}
}
* m = im
* samename = nil
* ptr = 0
2015-02-17 22:13:49 -05:00
return false
2015-02-13 14:40:36 -05:00
found :
}
2015-02-17 22:13:49 -05:00
return true
2015-02-13 14:40:36 -05:00
}
t = methtype ( t , 0 )
if t != nil {
expandmeth ( t )
}
2015-02-23 16:07:24 -05:00
var tm * Type
var imtype * Type
2015-09-08 20:29:10 +02:00
var followptr bool
2015-02-23 16:07:24 -05:00
var rcvr * Type
for im := iface . Type ; im != nil ; im = im . Down {
2015-10-03 09:35:40 -07:00
if im . Broke {
2015-08-21 22:24:20 -04:00
continue
}
2015-02-13 14:40:36 -05:00
imtype = methodfunc ( im . Type , nil )
tm = ifacelookdot ( im . Sym , t , & followptr , 0 )
2015-02-17 22:13:49 -05:00
if tm == nil || tm . Nointerface || ! Eqtype ( methodfunc ( tm . Type , nil ) , imtype ) {
2015-02-13 14:40:36 -05:00
if tm == nil {
tm = ifacelookdot ( im . Sym , t , & followptr , 1 )
}
* m = im
* samename = tm
* ptr = 0
2015-02-17 22:13:49 -05:00
return false
2015-02-13 14:40:36 -05:00
}
// if pointer receiver in method,
// the method does not exist for value types.
rcvr = getthisx ( tm . Type ) . Type . Type
2015-09-08 20:29:10 +02:00
if Isptr [ rcvr . Etype ] && ! Isptr [ t0 . Etype ] && ! followptr && ! isifacemethod ( tm . Type ) {
2015-02-13 14:40:36 -05:00
if false && Debug [ 'r' ] != 0 {
Yyerror ( "interface pointer mismatch" )
}
* m = im
* samename = nil
* ptr = 1
2015-02-17 22:13:49 -05:00
return false
2015-02-13 14:40:36 -05:00
}
}
2015-02-17 22:13:49 -05:00
return true
2015-02-13 14:40:36 -05:00
}
2015-10-22 09:51:12 +09:00
// even simpler simtype; get rid of ptr, bool.
// assuming that the front end has rejected
// all the invalid conversions (like ptr -> bool)
2015-09-24 23:21:18 +02:00
func Simsimtype ( t * Type ) EType {
2015-02-13 14:40:36 -05:00
if t == nil {
return 0
}
2015-09-24 23:21:18 +02:00
et := Simtype [ t . Etype ]
2015-02-13 14:40:36 -05:00
switch et {
case TPTR32 :
et = TUINT32
case TPTR64 :
et = TUINT64
case TBOOL :
et = TUINT8
}
return et
}
2015-05-22 22:01:01 -04:00
func listtreecopy ( l * NodeList , lineno int32 ) * NodeList {
2015-03-02 14:22:05 -05:00
var out * NodeList
2015-02-13 14:40:36 -05:00
for ; l != nil ; l = l . Next {
2015-05-22 22:01:01 -04:00
out = list ( out , treecopy ( l . N , lineno ) )
2015-02-13 14:40:36 -05:00
}
return out
}
func liststmt ( l * NodeList ) * Node {
2015-02-23 16:07:24 -05:00
n := Nod ( OBLOCK , nil , nil )
2015-02-13 14:40:36 -05:00
n . List = l
if l != nil {
n . Lineno = l . N . Lineno
}
return n
}
2015-10-22 09:51:12 +09:00
// return nelem of list
2015-02-13 14:40:36 -05:00
func structcount ( t * Type ) int {
var s Iter
2015-02-23 16:07:24 -05:00
v := 0
2015-02-13 14:40:36 -05:00
for t = Structfirst ( & s , & t ) ; t != nil ; t = structnext ( & s ) {
v ++
}
return v
}
2015-10-22 09:51:12 +09:00
// return power of 2 of the constant
// operand. -1 if it is not a power of 2.
// 1000+ if it is a -(power of 2)
2015-02-13 14:40:36 -05:00
func powtwo ( n * Node ) int {
if n == nil || n . Op != OLITERAL || n . Type == nil {
2015-03-02 12:35:15 -05:00
return - 1
2015-02-13 14:40:36 -05:00
}
2015-03-01 07:54:01 +00:00
if ! Isint [ n . Type . Etype ] {
2015-03-02 12:35:15 -05:00
return - 1
2015-02-13 14:40:36 -05:00
}
2015-05-27 00:47:05 -04:00
v := uint64 ( Mpgetfix ( n . Val ( ) . U . ( * Mpint ) ) )
2015-03-02 12:35:15 -05:00
b := uint64 ( 1 )
2015-02-23 16:07:24 -05:00
for i := 0 ; i < 64 ; i ++ {
2015-02-13 14:40:36 -05:00
if b == v {
return i
}
b = b << 1
}
2015-03-01 07:54:01 +00:00
if ! Issigned [ n . Type . Etype ] {
2015-03-02 12:35:15 -05:00
return - 1
2015-02-13 14:40:36 -05:00
}
v = - v
b = 1
2015-02-23 16:07:24 -05:00
for i := 0 ; i < 64 ; i ++ {
2015-02-13 14:40:36 -05:00
if b == v {
return i + 1000
}
b = b << 1
}
return - 1
}
2015-10-22 09:51:12 +09:00
// return the unsigned type for
// a signed integer type.
// returns T if input is not a
// signed integer type.
2015-02-13 14:40:36 -05:00
func tounsigned ( t * Type ) * Type {
// this is types[et+1], but not sure
// that this relation is immutable
switch t . Etype {
default :
2015-04-17 12:03:22 -04:00
fmt . Printf ( "tounsigned: unknown type %v\n" , t )
2015-02-13 14:40:36 -05:00
t = nil
case TINT :
t = Types [ TUINT ]
case TINT8 :
t = Types [ TUINT8 ]
case TINT16 :
t = Types [ TUINT16 ]
case TINT32 :
t = Types [ TUINT32 ]
case TINT64 :
t = Types [ TUINT64 ]
}
return t
}
2015-10-22 09:51:12 +09:00
// magic number for signed division
// see hacker's delight chapter 10
2015-02-13 14:40:36 -05:00
func Smagic ( m * Magic ) {
var mask uint64
m . Bad = 0
switch m . W {
default :
m . Bad = 1
return
case 8 :
mask = 0xff
case 16 :
mask = 0xffff
case 32 :
mask = 0xffffffff
case 64 :
mask = 0xffffffffffffffff
}
2015-02-23 16:07:24 -05:00
two31 := mask ^ ( mask >> 1 )
2015-02-13 14:40:36 -05:00
2015-02-23 16:07:24 -05:00
p := m . W - 1
ad := uint64 ( m . Sd )
2015-02-13 14:40:36 -05:00
if m . Sd < 0 {
ad = - uint64 ( m . Sd )
}
// bad denominators
if ad == 0 || ad == 1 || ad == two31 {
m . Bad = 1
return
}
2015-02-23 16:07:24 -05:00
t := two31
2015-02-13 14:40:36 -05:00
ad &= mask
2015-02-23 16:07:24 -05:00
anc := t - 1 - t % ad
2015-02-13 14:40:36 -05:00
anc &= mask
2015-02-23 16:07:24 -05:00
q1 := two31 / anc
r1 := two31 - q1 * anc
2015-02-13 14:40:36 -05:00
q1 &= mask
r1 &= mask
2015-02-23 16:07:24 -05:00
q2 := two31 / ad
r2 := two31 - q2 * ad
2015-02-13 14:40:36 -05:00
q2 &= mask
r2 &= mask
2015-02-23 16:07:24 -05:00
var delta uint64
2015-02-13 14:40:36 -05:00
for {
p ++
q1 <<= 1
r1 <<= 1
q1 &= mask
r1 &= mask
if r1 >= anc {
q1 ++
r1 -= anc
q1 &= mask
r1 &= mask
}
q2 <<= 1
r2 <<= 1
q2 &= mask
r2 &= mask
if r2 >= ad {
q2 ++
r2 -= ad
q2 &= mask
r2 &= mask
}
delta = ad - r2
delta &= mask
if q1 < delta || ( q1 == delta && r1 == 0 ) {
continue
}
break
}
m . Sm = int64 ( q2 + 1 )
if uint64 ( m . Sm ) & two31 != 0 {
m . Sm |= ^ int64 ( mask )
}
m . S = p - m . W
}
2015-10-22 09:51:12 +09:00
// magic number for unsigned division
// see hacker's delight chapter 10
2015-02-13 14:40:36 -05:00
func Umagic ( m * Magic ) {
var mask uint64
m . Bad = 0
m . Ua = 0
switch m . W {
default :
m . Bad = 1
return
case 8 :
mask = 0xff
case 16 :
mask = 0xffff
case 32 :
mask = 0xffffffff
case 64 :
mask = 0xffffffffffffffff
}
2015-02-23 16:07:24 -05:00
two31 := mask ^ ( mask >> 1 )
2015-02-13 14:40:36 -05:00
m . Ud &= mask
if m . Ud == 0 || m . Ud == two31 {
m . Bad = 1
return
}
2015-02-23 16:07:24 -05:00
nc := mask - ( - m . Ud & mask ) % m . Ud
p := m . W - 1
2015-02-13 14:40:36 -05:00
2015-02-23 16:07:24 -05:00
q1 := two31 / nc
r1 := two31 - q1 * nc
2015-02-13 14:40:36 -05:00
q1 &= mask
r1 &= mask
2015-02-23 16:07:24 -05:00
q2 := ( two31 - 1 ) / m . Ud
r2 := ( two31 - 1 ) - q2 * m . Ud
2015-02-13 14:40:36 -05:00
q2 &= mask
r2 &= mask
2015-02-23 16:07:24 -05:00
var delta uint64
2015-02-13 14:40:36 -05:00
for {
p ++
if r1 >= nc - r1 {
q1 <<= 1
q1 ++
r1 <<= 1
r1 -= nc
} else {
q1 <<= 1
r1 <<= 1
}
q1 &= mask
r1 &= mask
if r2 + 1 >= m . Ud - r2 {
if q2 >= two31 - 1 {
m . Ua = 1
}
q2 <<= 1
q2 ++
r2 <<= 1
r2 ++
r2 -= m . Ud
} else {
if q2 >= two31 {
m . Ua = 1
}
q2 <<= 1
r2 <<= 1
r2 ++
}
q2 &= mask
r2 &= mask
delta = m . Ud - 1 - r2
delta &= mask
if p < m . W + m . W {
if q1 < delta || ( q1 == delta && r1 == 0 ) {
continue
}
}
break
}
m . Um = q2 + 1
m . S = p - m . W
}
func ngotype ( n * Node ) * Sym {
if n . Type != nil {
return typenamesym ( n . Type )
}
return nil
}
2015-10-22 09:51:12 +09:00
// Convert raw string to the prefix that will be used in the symbol
// table. All control characters, space, '%' and '"', as well as
// non-7-bit clean bytes turn into %xx. The period needs escaping
// only in the last segment of the path, and it makes for happier
// users if we escape that as little as possible.
//
// If you edit this, edit ../../debug/goobj/read.go:/importPathToPrefix too.
2015-02-13 14:40:36 -05:00
func pathtoprefix ( s string ) string {
slash := strings . LastIndex ( s , "/" )
for i := 0 ; i < len ( s ) ; i ++ {
c := s [ i ]
if c <= ' ' || i >= slash && c == '.' || c == '%' || c == '"' || c >= 0x7F {
2015-03-02 12:35:15 -05:00
var buf bytes . Buffer
for i := 0 ; i < len ( s ) ; i ++ {
c := s [ i ]
if c <= ' ' || i >= slash && c == '.' || c == '%' || c == '"' || c >= 0x7F {
fmt . Fprintf ( & buf , "%%%02x" , c )
continue
}
buf . WriteByte ( c )
}
return buf . String ( )
2015-02-13 14:40:36 -05:00
}
}
return s
}
2015-03-02 16:21:15 -05:00
var pkgMap = make ( map [ string ] * Pkg )
var pkgs [ ] * Pkg
2015-03-02 16:03:26 -05:00
func mkpkg ( path string ) * Pkg {
2015-03-02 16:21:15 -05:00
if p := pkgMap [ path ] ; p != nil {
return p
2015-02-13 14:40:36 -05:00
}
2015-02-23 16:07:24 -05:00
p := new ( Pkg )
2015-03-02 16:03:26 -05:00
p . Path = path
p . Prefix = pathtoprefix ( path )
2015-03-12 18:45:30 -04:00
p . Syms = make ( map [ string ] * Sym )
2015-03-02 16:21:15 -05:00
pkgMap [ path ] = p
pkgs = append ( pkgs , p )
2015-02-13 14:40:36 -05:00
return p
}
func addinit ( np * * Node , init * NodeList ) {
if init == nil {
return
}
2015-02-23 16:07:24 -05:00
n := * np
2015-02-13 14:40:36 -05:00
switch n . Op {
// There may be multiple refs to this node;
// introduce OCONVNOP to hold init list.
2015-04-01 09:38:44 -07:00
case ONAME , OLITERAL :
2015-02-13 14:40:36 -05:00
n = Nod ( OCONVNOP , n , nil )
n . Type = n . Left . Type
n . Typecheck = 1
* np = n
}
n . Ninit = concat ( init , n . Ninit )
n . Ullman = UINF
}
var reservedimports = [ ] string {
"go" ,
"type" ,
}
2015-03-02 16:03:26 -05:00
func isbadimport ( path string ) bool {
if strings . Contains ( path , "\x00" ) {
2015-02-13 14:40:36 -05:00
Yyerror ( "import path contains NUL" )
return true
}
2015-09-08 22:22:44 +02:00
for _ , ri := range reservedimports {
if path == ri {
2015-03-02 16:03:26 -05:00
Yyerror ( "import path %q is reserved and cannot be used" , path )
2015-02-13 14:40:36 -05:00
return true
}
}
2015-03-02 16:03:26 -05:00
for _ , r := range path {
2015-02-13 14:40:36 -05:00
if r == utf8 . RuneError {
2015-03-02 16:03:26 -05:00
Yyerror ( "import path contains invalid UTF-8 sequence: %q" , path )
2015-02-13 14:40:36 -05:00
return true
}
if r < 0x20 || r == 0x7f {
2015-03-02 16:03:26 -05:00
Yyerror ( "import path contains control character: %q" , path )
2015-02-13 14:40:36 -05:00
return true
}
if r == '\\' {
2015-03-02 16:03:26 -05:00
Yyerror ( "import path contains backslash; use slash: %q" , path )
2015-02-13 14:40:36 -05:00
return true
}
if unicode . IsSpace ( rune ( r ) ) {
2015-03-02 16:03:26 -05:00
Yyerror ( "import path contains space character: %q" , path )
2015-02-13 14:40:36 -05:00
return true
}
if strings . ContainsRune ( "!\"#$%&'()*,:;<=>?[]^`{|}" , r ) {
2015-03-02 16:03:26 -05:00
Yyerror ( "import path contains invalid character '%c': %q" , r , path )
2015-02-13 14:40:36 -05:00
return true
}
}
return false
}
func checknil ( x * Node , init * * NodeList ) {
2015-02-17 22:13:49 -05:00
if Isinter ( x . Type ) {
2015-02-13 14:40:36 -05:00
x = Nod ( OITAB , x , nil )
typecheck ( & x , Erv )
}
2015-02-23 16:07:24 -05:00
n := Nod ( OCHECKNIL , x , nil )
2015-02-13 14:40:36 -05:00
n . Typecheck = 1
* init = list ( * init , n )
}
2015-10-22 09:51:12 +09:00
// Can this type be stored directly in an interface word?
// Yes, if the representation is a single pointer.
2015-02-17 22:13:49 -05:00
func isdirectiface ( t * Type ) bool {
2015-02-13 14:40:36 -05:00
switch t . Etype {
case TPTR32 ,
TPTR64 ,
TCHAN ,
TMAP ,
TFUNC ,
TUNSAFEPTR :
2015-02-17 22:13:49 -05:00
return true
2015-02-13 14:40:36 -05:00
// Array of 1 direct iface type can be direct.
case TARRAY :
2015-02-17 22:13:49 -05:00
return t . Bound == 1 && isdirectiface ( t . Type )
2015-02-13 14:40:36 -05:00
// Struct with 1 field of direct iface type can be direct.
case TSTRUCT :
2015-02-17 22:13:49 -05:00
return t . Type != nil && t . Type . Down == nil && isdirectiface ( t . Type . Type )
2015-02-13 14:40:36 -05:00
}
2015-02-17 22:13:49 -05:00
return false
2015-02-13 14:40:36 -05:00
}
2015-03-17 13:56:29 -07:00
2015-03-19 23:38:24 +00:00
// type2IET returns "T" if t is a concrete type,
// "I" if t is an interface type, and "E" if t is an empty interface type.
2015-03-17 13:56:29 -07:00
// It is used to build calls to the conv* and assert* runtime routines.
2015-03-19 23:38:24 +00:00
func type2IET ( t * Type ) string {
2015-03-17 13:56:29 -07:00
if isnilinter ( t ) {
return "E"
}
if Isinter ( t ) {
return "I"
}
return "T"
}