Home | History | Annotate | Download | only in gc
      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 import "cmd/internal/obj"
      8 
      9 /*
     10  * look for
     11  *	unsafe.Sizeof
     12  *	unsafe.Offsetof
     13  *	unsafe.Alignof
     14  * rewrite with a constant
     15  */
     16 func unsafenmagic(nn *Node) *Node {
     17 	fn := nn.Left
     18 	args := nn.List
     19 
     20 	if safemode != 0 || fn == nil || fn.Op != ONAME {
     21 		return nil
     22 	}
     23 	s := fn.Sym
     24 	if s == nil {
     25 		return nil
     26 	}
     27 	if s.Pkg != unsafepkg {
     28 		return nil
     29 	}
     30 
     31 	if args == nil {
     32 		Yyerror("missing argument for %v", s)
     33 		return nil
     34 	}
     35 
     36 	r := args.N
     37 
     38 	var v int64
     39 	if s.Name == "Sizeof" {
     40 		typecheck(&r, Erv)
     41 		defaultlit(&r, nil)
     42 		tr := r.Type
     43 		if tr == nil {
     44 			goto bad
     45 		}
     46 		dowidth(tr)
     47 		v = tr.Width
     48 		goto yes
     49 	}
     50 
     51 	if s.Name == "Offsetof" {
     52 		// must be a selector.
     53 		if r.Op != OXDOT {
     54 			goto bad
     55 		}
     56 
     57 		// Remember base of selector to find it back after dot insertion.
     58 		// Since r->left may be mutated by typechecking, check it explicitly
     59 		// first to track it correctly.
     60 		typecheck(&r.Left, Erv)
     61 
     62 		base := r.Left
     63 		typecheck(&r, Erv)
     64 		switch r.Op {
     65 		case ODOT, ODOTPTR:
     66 			break
     67 
     68 		case OCALLPART:
     69 			Yyerror("invalid expression %v: argument is a method value", nn)
     70 			v = 0
     71 			goto ret
     72 
     73 		default:
     74 			goto bad
     75 		}
     76 
     77 		v = 0
     78 
     79 		// add offsets for inserted dots.
     80 		var r1 *Node
     81 		for r1 = r; r1.Left != base; r1 = r1.Left {
     82 			switch r1.Op {
     83 			case ODOT:
     84 				v += r1.Xoffset
     85 
     86 			case ODOTPTR:
     87 				Yyerror("invalid expression %v: selector implies indirection of embedded %v", nn, r1.Left)
     88 				goto ret
     89 
     90 			default:
     91 				Dump("unsafenmagic", r)
     92 				Fatal("impossible %v node after dot insertion", Oconv(int(r1.Op), obj.FmtSharp))
     93 				goto bad
     94 			}
     95 		}
     96 
     97 		v += r1.Xoffset
     98 		goto yes
     99 	}
    100 
    101 	if s.Name == "Alignof" {
    102 		typecheck(&r, Erv)
    103 		defaultlit(&r, nil)
    104 		tr := r.Type
    105 		if tr == nil {
    106 			goto bad
    107 		}
    108 
    109 		// make struct { byte; T; }
    110 		t := typ(TSTRUCT)
    111 
    112 		t.Type = typ(TFIELD)
    113 		t.Type.Type = Types[TUINT8]
    114 		t.Type.Down = typ(TFIELD)
    115 		t.Type.Down.Type = tr
    116 
    117 		// compute struct widths
    118 		dowidth(t)
    119 
    120 		// the offset of T is its required alignment
    121 		v = t.Type.Down.Width
    122 
    123 		goto yes
    124 	}
    125 
    126 	return nil
    127 
    128 bad:
    129 	Yyerror("invalid expression %v", nn)
    130 	v = 0
    131 	goto ret
    132 
    133 yes:
    134 	if args.Next != nil {
    135 		Yyerror("extra arguments for %v", s)
    136 	}
    137 
    138 	// any side effects disappear; ignore init
    139 ret:
    140 	var val Val
    141 	val.U = new(Mpint)
    142 	Mpmovecfix(val.U.(*Mpint), v)
    143 	n := Nod(OLITERAL, nil, nil)
    144 	n.Orig = nn
    145 	n.SetVal(val)
    146 	n.Type = Types[TUINTPTR]
    147 	nn.Type = Types[TUINTPTR]
    148 	return n
    149 }
    150 
    151 func isunsafebuiltin(n *Node) bool {
    152 	if n == nil || n.Op != ONAME || n.Sym == nil || n.Sym.Pkg != unsafepkg {
    153 		return false
    154 	}
    155 	if n.Sym.Name == "Sizeof" {
    156 		return true
    157 	}
    158 	if n.Sym.Name == "Offsetof" {
    159 		return true
    160 	}
    161 	if n.Sym.Name == "Alignof" {
    162 		return true
    163 	}
    164 	return false
    165 }
    166