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