]>
Commit | Line | Data |
---|---|---|
15c0b25d AP |
1 | // Go support for Protocol Buffers - Google's data interchange format |
2 | // | |
3 | // Copyright 2012 The Go Authors. All rights reserved. | |
4 | // https://github.com/golang/protobuf | |
5 | // | |
6 | // Redistribution and use in source and binary forms, with or without | |
7 | // modification, are permitted provided that the following conditions are | |
8 | // met: | |
9 | // | |
10 | // * Redistributions of source code must retain the above copyright | |
11 | // notice, this list of conditions and the following disclaimer. | |
12 | // * Redistributions in binary form must reproduce the above | |
13 | // copyright notice, this list of conditions and the following disclaimer | |
14 | // in the documentation and/or other materials provided with the | |
15 | // distribution. | |
16 | // * Neither the name of Google Inc. nor the names of its | |
17 | // contributors may be used to endorse or promote products derived from | |
18 | // this software without specific prior written permission. | |
19 | // | |
20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
21 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
22 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
23 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
24 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
26 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
27 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
28 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
29 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
30 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
31 | ||
32 | // +build !purego,!appengine,!js | |
33 | ||
34 | // This file contains the implementation of the proto field accesses using package unsafe. | |
35 | ||
36 | package proto | |
37 | ||
38 | import ( | |
39 | "reflect" | |
40 | "sync/atomic" | |
41 | "unsafe" | |
42 | ) | |
43 | ||
44 | const unsafeAllowed = true | |
45 | ||
46 | // A field identifies a field in a struct, accessible from a pointer. | |
47 | // In this implementation, a field is identified by its byte offset from the start of the struct. | |
48 | type field uintptr | |
49 | ||
50 | // toField returns a field equivalent to the given reflect field. | |
51 | func toField(f *reflect.StructField) field { | |
52 | return field(f.Offset) | |
53 | } | |
54 | ||
55 | // invalidField is an invalid field identifier. | |
56 | const invalidField = ^field(0) | |
57 | ||
58 | // zeroField is a noop when calling pointer.offset. | |
59 | const zeroField = field(0) | |
60 | ||
61 | // IsValid reports whether the field identifier is valid. | |
62 | func (f field) IsValid() bool { | |
63 | return f != invalidField | |
64 | } | |
65 | ||
66 | // The pointer type below is for the new table-driven encoder/decoder. | |
67 | // The implementation here uses unsafe.Pointer to create a generic pointer. | |
68 | // In pointer_reflect.go we use reflect instead of unsafe to implement | |
69 | // the same (but slower) interface. | |
70 | type pointer struct { | |
71 | p unsafe.Pointer | |
72 | } | |
73 | ||
74 | // size of pointer | |
75 | var ptrSize = unsafe.Sizeof(uintptr(0)) | |
76 | ||
77 | // toPointer converts an interface of pointer type to a pointer | |
78 | // that points to the same target. | |
79 | func toPointer(i *Message) pointer { | |
80 | // Super-tricky - read pointer out of data word of interface value. | |
81 | // Saves ~25ns over the equivalent: | |
82 | // return valToPointer(reflect.ValueOf(*i)) | |
83 | return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]} | |
84 | } | |
85 | ||
86 | // toAddrPointer converts an interface to a pointer that points to | |
87 | // the interface data. | |
107c1cdb | 88 | func toAddrPointer(i *interface{}, isptr, deref bool) (p pointer) { |
15c0b25d AP |
89 | // Super-tricky - read or get the address of data word of interface value. |
90 | if isptr { | |
91 | // The interface is of pointer type, thus it is a direct interface. | |
92 | // The data word is the pointer data itself. We take its address. | |
107c1cdb ND |
93 | p = pointer{p: unsafe.Pointer(uintptr(unsafe.Pointer(i)) + ptrSize)} |
94 | } else { | |
95 | // The interface is not of pointer type. The data word is the pointer | |
96 | // to the data. | |
97 | p = pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]} | |
15c0b25d | 98 | } |
107c1cdb ND |
99 | if deref { |
100 | p.p = *(*unsafe.Pointer)(p.p) | |
101 | } | |
102 | return p | |
15c0b25d AP |
103 | } |
104 | ||
105 | // valToPointer converts v to a pointer. v must be of pointer type. | |
106 | func valToPointer(v reflect.Value) pointer { | |
107 | return pointer{p: unsafe.Pointer(v.Pointer())} | |
108 | } | |
109 | ||
110 | // offset converts from a pointer to a structure to a pointer to | |
111 | // one of its fields. | |
112 | func (p pointer) offset(f field) pointer { | |
113 | // For safety, we should panic if !f.IsValid, however calling panic causes | |
114 | // this to no longer be inlineable, which is a serious performance cost. | |
115 | /* | |
116 | if !f.IsValid() { | |
117 | panic("invalid field") | |
118 | } | |
119 | */ | |
120 | return pointer{p: unsafe.Pointer(uintptr(p.p) + uintptr(f))} | |
121 | } | |
122 | ||
123 | func (p pointer) isNil() bool { | |
124 | return p.p == nil | |
125 | } | |
126 | ||
127 | func (p pointer) toInt64() *int64 { | |
128 | return (*int64)(p.p) | |
129 | } | |
130 | func (p pointer) toInt64Ptr() **int64 { | |
131 | return (**int64)(p.p) | |
132 | } | |
133 | func (p pointer) toInt64Slice() *[]int64 { | |
134 | return (*[]int64)(p.p) | |
135 | } | |
136 | func (p pointer) toInt32() *int32 { | |
137 | return (*int32)(p.p) | |
138 | } | |
139 | ||
140 | // See pointer_reflect.go for why toInt32Ptr/Slice doesn't exist. | |
141 | /* | |
142 | func (p pointer) toInt32Ptr() **int32 { | |
143 | return (**int32)(p.p) | |
144 | } | |
145 | func (p pointer) toInt32Slice() *[]int32 { | |
146 | return (*[]int32)(p.p) | |
147 | } | |
148 | */ | |
149 | func (p pointer) getInt32Ptr() *int32 { | |
150 | return *(**int32)(p.p) | |
151 | } | |
152 | func (p pointer) setInt32Ptr(v int32) { | |
153 | *(**int32)(p.p) = &v | |
154 | } | |
155 | ||
156 | // getInt32Slice loads a []int32 from p. | |
157 | // The value returned is aliased with the original slice. | |
158 | // This behavior differs from the implementation in pointer_reflect.go. | |
159 | func (p pointer) getInt32Slice() []int32 { | |
160 | return *(*[]int32)(p.p) | |
161 | } | |
162 | ||
163 | // setInt32Slice stores a []int32 to p. | |
164 | // The value set is aliased with the input slice. | |
165 | // This behavior differs from the implementation in pointer_reflect.go. | |
166 | func (p pointer) setInt32Slice(v []int32) { | |
167 | *(*[]int32)(p.p) = v | |
168 | } | |
169 | ||
170 | // TODO: Can we get rid of appendInt32Slice and use setInt32Slice instead? | |
171 | func (p pointer) appendInt32Slice(v int32) { | |
172 | s := (*[]int32)(p.p) | |
173 | *s = append(*s, v) | |
174 | } | |
175 | ||
176 | func (p pointer) toUint64() *uint64 { | |
177 | return (*uint64)(p.p) | |
178 | } | |
179 | func (p pointer) toUint64Ptr() **uint64 { | |
180 | return (**uint64)(p.p) | |
181 | } | |
182 | func (p pointer) toUint64Slice() *[]uint64 { | |
183 | return (*[]uint64)(p.p) | |
184 | } | |
185 | func (p pointer) toUint32() *uint32 { | |
186 | return (*uint32)(p.p) | |
187 | } | |
188 | func (p pointer) toUint32Ptr() **uint32 { | |
189 | return (**uint32)(p.p) | |
190 | } | |
191 | func (p pointer) toUint32Slice() *[]uint32 { | |
192 | return (*[]uint32)(p.p) | |
193 | } | |
194 | func (p pointer) toBool() *bool { | |
195 | return (*bool)(p.p) | |
196 | } | |
197 | func (p pointer) toBoolPtr() **bool { | |
198 | return (**bool)(p.p) | |
199 | } | |
200 | func (p pointer) toBoolSlice() *[]bool { | |
201 | return (*[]bool)(p.p) | |
202 | } | |
203 | func (p pointer) toFloat64() *float64 { | |
204 | return (*float64)(p.p) | |
205 | } | |
206 | func (p pointer) toFloat64Ptr() **float64 { | |
207 | return (**float64)(p.p) | |
208 | } | |
209 | func (p pointer) toFloat64Slice() *[]float64 { | |
210 | return (*[]float64)(p.p) | |
211 | } | |
212 | func (p pointer) toFloat32() *float32 { | |
213 | return (*float32)(p.p) | |
214 | } | |
215 | func (p pointer) toFloat32Ptr() **float32 { | |
216 | return (**float32)(p.p) | |
217 | } | |
218 | func (p pointer) toFloat32Slice() *[]float32 { | |
219 | return (*[]float32)(p.p) | |
220 | } | |
221 | func (p pointer) toString() *string { | |
222 | return (*string)(p.p) | |
223 | } | |
224 | func (p pointer) toStringPtr() **string { | |
225 | return (**string)(p.p) | |
226 | } | |
227 | func (p pointer) toStringSlice() *[]string { | |
228 | return (*[]string)(p.p) | |
229 | } | |
230 | func (p pointer) toBytes() *[]byte { | |
231 | return (*[]byte)(p.p) | |
232 | } | |
233 | func (p pointer) toBytesSlice() *[][]byte { | |
234 | return (*[][]byte)(p.p) | |
235 | } | |
236 | func (p pointer) toExtensions() *XXX_InternalExtensions { | |
237 | return (*XXX_InternalExtensions)(p.p) | |
238 | } | |
239 | func (p pointer) toOldExtensions() *map[int32]Extension { | |
240 | return (*map[int32]Extension)(p.p) | |
241 | } | |
242 | ||
243 | // getPointerSlice loads []*T from p as a []pointer. | |
244 | // The value returned is aliased with the original slice. | |
245 | // This behavior differs from the implementation in pointer_reflect.go. | |
246 | func (p pointer) getPointerSlice() []pointer { | |
247 | // Super-tricky - p should point to a []*T where T is a | |
248 | // message type. We load it as []pointer. | |
249 | return *(*[]pointer)(p.p) | |
250 | } | |
251 | ||
252 | // setPointerSlice stores []pointer into p as a []*T. | |
253 | // The value set is aliased with the input slice. | |
254 | // This behavior differs from the implementation in pointer_reflect.go. | |
255 | func (p pointer) setPointerSlice(v []pointer) { | |
256 | // Super-tricky - p should point to a []*T where T is a | |
257 | // message type. We store it as []pointer. | |
258 | *(*[]pointer)(p.p) = v | |
259 | } | |
260 | ||
261 | // getPointer loads the pointer at p and returns it. | |
262 | func (p pointer) getPointer() pointer { | |
263 | return pointer{p: *(*unsafe.Pointer)(p.p)} | |
264 | } | |
265 | ||
266 | // setPointer stores the pointer q at p. | |
267 | func (p pointer) setPointer(q pointer) { | |
268 | *(*unsafe.Pointer)(p.p) = q.p | |
269 | } | |
270 | ||
271 | // append q to the slice pointed to by p. | |
272 | func (p pointer) appendPointer(q pointer) { | |
273 | s := (*[]unsafe.Pointer)(p.p) | |
274 | *s = append(*s, q.p) | |
275 | } | |
276 | ||
277 | // getInterfacePointer returns a pointer that points to the | |
278 | // interface data of the interface pointed by p. | |
279 | func (p pointer) getInterfacePointer() pointer { | |
280 | // Super-tricky - read pointer out of data word of interface value. | |
281 | return pointer{p: (*(*[2]unsafe.Pointer)(p.p))[1]} | |
282 | } | |
283 | ||
284 | // asPointerTo returns a reflect.Value that is a pointer to an | |
285 | // object of type t stored at p. | |
286 | func (p pointer) asPointerTo(t reflect.Type) reflect.Value { | |
287 | return reflect.NewAt(t, p.p) | |
288 | } | |
289 | ||
290 | func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo { | |
291 | return (*unmarshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) | |
292 | } | |
293 | func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) { | |
294 | atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) | |
295 | } | |
296 | func atomicLoadMarshalInfo(p **marshalInfo) *marshalInfo { | |
297 | return (*marshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) | |
298 | } | |
299 | func atomicStoreMarshalInfo(p **marshalInfo, v *marshalInfo) { | |
300 | atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) | |
301 | } | |
302 | func atomicLoadMergeInfo(p **mergeInfo) *mergeInfo { | |
303 | return (*mergeInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) | |
304 | } | |
305 | func atomicStoreMergeInfo(p **mergeInfo, v *mergeInfo) { | |
306 | atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) | |
307 | } | |
308 | func atomicLoadDiscardInfo(p **discardInfo) *discardInfo { | |
309 | return (*discardInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p)))) | |
310 | } | |
311 | func atomicStoreDiscardInfo(p **discardInfo, v *discardInfo) { | |
312 | atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v)) | |
313 | } |