github.com/euank/go@v0.0.0-20160829210321-495514729181/src/cmd/compile/internal/gc/unsafe.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package gc
     6  
     7  // unsafenmagic rewrites calls to package unsafe's functions into constants.
     8  func unsafenmagic(nn *Node) *Node {
     9  	fn := nn.Left
    10  	args := nn.List
    11  
    12  	if safemode || fn == nil || fn.Op != ONAME {
    13  		return nil
    14  	}
    15  	s := fn.Sym
    16  	if s == nil {
    17  		return nil
    18  	}
    19  	if s.Pkg != unsafepkg {
    20  		return nil
    21  	}
    22  
    23  	if args.Len() == 0 {
    24  		Yyerror("missing argument for %v", s)
    25  		return nil
    26  	}
    27  
    28  	r := args.First()
    29  
    30  	var v int64
    31  	switch s.Name {
    32  	case "Alignof", "Sizeof":
    33  		r = typecheck(r, Erv)
    34  		r = defaultlit(r, nil)
    35  		tr := r.Type
    36  		if tr == nil {
    37  			goto bad
    38  		}
    39  		dowidth(tr)
    40  		if s.Name == "Alignof" {
    41  			v = int64(tr.Align)
    42  		} else {
    43  			v = tr.Width
    44  		}
    45  
    46  	case "Offsetof":
    47  		// must be a selector.
    48  		if r.Op != OXDOT {
    49  			goto bad
    50  		}
    51  
    52  		// Remember base of selector to find it back after dot insertion.
    53  		// Since r->left may be mutated by typechecking, check it explicitly
    54  		// first to track it correctly.
    55  		r.Left = typecheck(r.Left, Erv)
    56  		base := r.Left
    57  
    58  		r = typecheck(r, Erv)
    59  		switch r.Op {
    60  		case ODOT, ODOTPTR:
    61  			break
    62  		case OCALLPART:
    63  			Yyerror("invalid expression %v: argument is a method value", nn)
    64  			goto ret
    65  		default:
    66  			goto bad
    67  		}
    68  
    69  		// Sum offsets for dots until we reach base.
    70  		for r1 := r; r1 != base; r1 = r1.Left {
    71  			switch r1.Op {
    72  			case ODOTPTR:
    73  				// For Offsetof(s.f), s may itself be a pointer,
    74  				// but accessing f must not otherwise involve
    75  				// indirection via embedded pointer types.
    76  				if r1.Left != base {
    77  					Yyerror("invalid expression %v: selector implies indirection of embedded %v", nn, r1.Left)
    78  					goto ret
    79  				}
    80  				fallthrough
    81  			case ODOT:
    82  				v += r1.Xoffset
    83  			default:
    84  				Dump("unsafenmagic", r)
    85  				Fatalf("impossible %#v node after dot insertion", r1.Op)
    86  				goto bad
    87  			}
    88  		}
    89  
    90  	default:
    91  		return nil
    92  	}
    93  
    94  	if args.Len() > 1 {
    95  		Yyerror("extra arguments for %v", s)
    96  	}
    97  	goto ret
    98  
    99  bad:
   100  	Yyerror("invalid expression %v", nn)
   101  
   102  ret:
   103  	// any side effects disappear; ignore init
   104  	var val Val
   105  	val.U = new(Mpint)
   106  	val.U.(*Mpint).SetInt64(v)
   107  	n := Nod(OLITERAL, nil, nil)
   108  	n.Orig = nn
   109  	n.SetVal(val)
   110  	n.Type = Types[TUINTPTR]
   111  	nn.Type = Types[TUINTPTR]
   112  	return n
   113  }
   114  
   115  func isunsafebuiltin(n *Node) bool {
   116  	if n == nil || n.Op != ONAME || n.Sym == nil || n.Sym.Pkg != unsafepkg {
   117  		return false
   118  	}
   119  	if n.Sym.Name == "Sizeof" {
   120  		return true
   121  	}
   122  	if n.Sym.Name == "Offsetof" {
   123  		return true
   124  	}
   125  	if n.Sym.Name == "Alignof" {
   126  		return true
   127  	}
   128  	return false
   129  }