1 | // Copyright 2013 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 ssa |
6 | |
7 | // lvalues are the union of addressable expressions and map-index |
8 | // expressions. |
9 | |
10 | import ( |
11 | "go/ast" |
12 | "go/token" |
13 | "go/types" |
14 | ) |
15 | |
16 | // An lvalue represents an assignable location that may appear on the |
17 | // left-hand side of an assignment. This is a generalization of a |
18 | // pointer to permit updates to elements of maps. |
19 | type lvalue interface { |
20 | store(fn *Function, v Value) // stores v into the location |
21 | load(fn *Function) Value // loads the contents of the location |
22 | address(fn *Function) Value // address of the location |
23 | typ() types.Type // returns the type of the location |
24 | } |
25 | |
26 | // An address is an lvalue represented by a true pointer. |
27 | type address struct { |
28 | addr Value |
29 | pos token.Pos // source position |
30 | expr ast.Expr // source syntax of the value (not address) [debug mode] |
31 | } |
32 | |
33 | func (a *address) load(fn *Function) Value { |
34 | load := emitLoad(fn, a.addr) |
35 | load.pos = a.pos |
36 | return load |
37 | } |
38 | |
39 | func (a *address) store(fn *Function, v Value) { |
40 | store := emitStore(fn, a.addr, v, a.pos) |
41 | if a.expr != nil { |
42 | // store.Val is v, converted for assignability. |
43 | emitDebugRef(fn, a.expr, store.Val, false) |
44 | } |
45 | } |
46 | |
47 | func (a *address) address(fn *Function) Value { |
48 | if a.expr != nil { |
49 | emitDebugRef(fn, a.expr, a.addr, true) |
50 | } |
51 | return a.addr |
52 | } |
53 | |
54 | func (a *address) typ() types.Type { |
55 | return deref(a.addr.Type()) |
56 | } |
57 | |
58 | // An element is an lvalue represented by m[k], the location of an |
59 | // element of a map. These locations are not addressable |
60 | // since pointers cannot be formed from them, but they do support |
61 | // load() and store(). |
62 | type element struct { |
63 | m, k Value // map |
64 | t types.Type // map element type |
65 | pos token.Pos // source position of colon ({k:v}) or lbrack (m[k]=v) |
66 | } |
67 | |
68 | func (e *element) load(fn *Function) Value { |
69 | l := &Lookup{ |
70 | X: e.m, |
71 | Index: e.k, |
72 | } |
73 | l.setPos(e.pos) |
74 | l.setType(e.t) |
75 | return fn.emit(l) |
76 | } |
77 | |
78 | func (e *element) store(fn *Function, v Value) { |
79 | up := &MapUpdate{ |
80 | Map: e.m, |
81 | Key: e.k, |
82 | Value: emitConv(fn, v, e.t), |
83 | } |
84 | up.pos = e.pos |
85 | fn.emit(up) |
86 | } |
87 | |
88 | func (e *element) address(fn *Function) Value { |
89 | panic("map elements are not addressable") |
90 | } |
91 | |
92 | func (e *element) typ() types.Type { |
93 | return e.t |
94 | } |
95 | |
96 | // A lazyAddress is an lvalue whose address is the result of an instruction. |
97 | // These work like an *address except a new address.address() Value |
98 | // is created on each load, store and address call. |
99 | // A lazyAddress can be used to control when a side effect (nil pointer |
100 | // dereference, index out of bounds) of using a location happens. |
101 | type lazyAddress struct { |
102 | addr func(fn *Function) Value // emit to fn the computation of the address |
103 | t types.Type // type of the location |
104 | pos token.Pos // source position |
105 | expr ast.Expr // source syntax of the value (not address) [debug mode] |
106 | } |
107 | |
108 | func (l *lazyAddress) load(fn *Function) Value { |
109 | load := emitLoad(fn, l.addr(fn)) |
110 | load.pos = l.pos |
111 | return load |
112 | } |
113 | |
114 | func (l *lazyAddress) store(fn *Function, v Value) { |
115 | store := emitStore(fn, l.addr(fn), v, l.pos) |
116 | if l.expr != nil { |
117 | // store.Val is v, converted for assignability. |
118 | emitDebugRef(fn, l.expr, store.Val, false) |
119 | } |
120 | } |
121 | |
122 | func (l *lazyAddress) address(fn *Function) Value { |
123 | addr := l.addr(fn) |
124 | if l.expr != nil { |
125 | emitDebugRef(fn, l.expr, addr, true) |
126 | } |
127 | return addr |
128 | } |
129 | |
130 | func (l *lazyAddress) typ() types.Type { return l.t } |
131 | |
132 | // A blank is a dummy variable whose name is "_". |
133 | // It is not reified: loads are illegal and stores are ignored. |
134 | type blank struct{} |
135 | |
136 | func (bl blank) load(fn *Function) Value { |
137 | panic("blank.load is illegal") |
138 | } |
139 | |
140 | func (bl blank) store(fn *Function, v Value) { |
141 | // no-op |
142 | } |
143 | |
144 | func (bl blank) address(fn *Function) Value { |
145 | panic("blank var is not addressable") |
146 | } |
147 | |
148 | func (bl blank) typ() types.Type { |
149 | // This should be the type of the blank Ident; the typechecker |
150 | // doesn't provide this yet, but fortunately, we don't need it |
151 | // yet either. |
152 | panic("blank.typ is unimplemented") |
153 | } |
154 |
Members