blob: 7b69878c881e50323bb9f4d66d76a51ce18fcfd7 [file] [log] [blame]
Joe Tsaieeca8bb2018-12-04 16:24:22 -08001// Copyright 2012 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// +build !purego
6
7package protoV1
8
9import (
10 "reflect"
11 "sync/atomic"
12 "unsafe"
13
14 "github.com/golang/protobuf/protoapi"
15)
16
17// A field identifies a field in a struct, accessible from a pointer.
18// In this implementation, a field is identified by its byte offset from the start of the struct.
19type field uintptr
20
21// toField returns a field equivalent to the given reflect field.
22func toField(f *reflect.StructField) field {
23 return field(f.Offset)
24}
25
26// invalidField is an invalid field identifier.
27const invalidField = ^field(0)
28
29// zeroField is a noop when calling pointer.offset.
30const zeroField = field(0)
31
32// IsValid reports whether the field identifier is valid.
33func (f field) IsValid() bool {
34 return f != invalidField
35}
36
37// The pointer type below is for the new table-driven encoder/decoder.
38// The implementation here uses unsafe.Pointer to create a generic pointer.
39// In pointer_reflect.go we use reflect instead of unsafe to implement
40// the same (but slower) interface.
41type pointer struct {
42 p unsafe.Pointer
43}
44
45// toPointer converts an interface of pointer type to a pointer
46// that points to the same target.
47func toPointer(i *Message) pointer {
48 // Super-tricky - read pointer out of data word of interface value.
49 // Saves ~25ns over the equivalent:
50 // return valToPointer(reflect.ValueOf(*i))
51 return pointer{p: (*[2]unsafe.Pointer)(unsafe.Pointer(i))[1]}
52}
53
54// valToPointer converts v to a pointer. v must be of pointer type.
55func valToPointer(v reflect.Value) pointer {
56 return pointer{p: unsafe.Pointer(v.Pointer())}
57}
58
59// offset converts from a pointer to a structure to a pointer to
60// one of its fields.
61func (p pointer) offset(f field) pointer {
62 // For safety, we should panic if !f.IsValid, however calling panic causes
63 // this to no longer be inlineable, which is a serious performance cost.
64 /*
65 if !f.IsValid() {
66 panic("invalid field")
67 }
68 */
69 return pointer{p: unsafe.Pointer(uintptr(p.p) + uintptr(f))}
70}
71
72func (p pointer) isNil() bool {
73 return p.p == nil
74}
75
76func (p pointer) toInt64() *int64 {
77 return (*int64)(p.p)
78}
79func (p pointer) toInt64Ptr() **int64 {
80 return (**int64)(p.p)
81}
82func (p pointer) toInt64Slice() *[]int64 {
83 return (*[]int64)(p.p)
84}
85func (p pointer) toInt32() *int32 {
86 return (*int32)(p.p)
87}
88
89// See pointer_reflect.go for why toInt32Ptr/Slice doesn't exist.
90/*
91 func (p pointer) toInt32Ptr() **int32 {
92 return (**int32)(p.p)
93 }
94 func (p pointer) toInt32Slice() *[]int32 {
95 return (*[]int32)(p.p)
96 }
97*/
98func (p pointer) setInt32Ptr(v int32) {
99 *(**int32)(p.p) = &v
100}
101
102// TODO: Can we get rid of appendInt32Slice and use setInt32Slice instead?
103func (p pointer) appendInt32Slice(v int32) {
104 s := (*[]int32)(p.p)
105 *s = append(*s, v)
106}
107
108func (p pointer) toUint64() *uint64 {
109 return (*uint64)(p.p)
110}
111func (p pointer) toUint64Ptr() **uint64 {
112 return (**uint64)(p.p)
113}
114func (p pointer) toUint64Slice() *[]uint64 {
115 return (*[]uint64)(p.p)
116}
117func (p pointer) toUint32() *uint32 {
118 return (*uint32)(p.p)
119}
120func (p pointer) toUint32Ptr() **uint32 {
121 return (**uint32)(p.p)
122}
123func (p pointer) toUint32Slice() *[]uint32 {
124 return (*[]uint32)(p.p)
125}
126func (p pointer) toBool() *bool {
127 return (*bool)(p.p)
128}
129func (p pointer) toBoolPtr() **bool {
130 return (**bool)(p.p)
131}
132func (p pointer) toBoolSlice() *[]bool {
133 return (*[]bool)(p.p)
134}
135func (p pointer) toFloat64() *float64 {
136 return (*float64)(p.p)
137}
138func (p pointer) toFloat64Ptr() **float64 {
139 return (**float64)(p.p)
140}
141func (p pointer) toFloat64Slice() *[]float64 {
142 return (*[]float64)(p.p)
143}
144func (p pointer) toFloat32() *float32 {
145 return (*float32)(p.p)
146}
147func (p pointer) toFloat32Ptr() **float32 {
148 return (**float32)(p.p)
149}
150func (p pointer) toFloat32Slice() *[]float32 {
151 return (*[]float32)(p.p)
152}
153func (p pointer) toString() *string {
154 return (*string)(p.p)
155}
156func (p pointer) toStringPtr() **string {
157 return (**string)(p.p)
158}
159func (p pointer) toStringSlice() *[]string {
160 return (*[]string)(p.p)
161}
162func (p pointer) toBytes() *[]byte {
163 return (*[]byte)(p.p)
164}
165func (p pointer) toBytesSlice() *[][]byte {
166 return (*[][]byte)(p.p)
167}
168func (p pointer) toExtensions() *protoapi.XXX_InternalExtensions {
169 return (*protoapi.XXX_InternalExtensions)(p.p)
170}
171func (p pointer) toOldExtensions() *map[int32]protoapi.ExtensionField {
172 return (*map[int32]protoapi.ExtensionField)(p.p)
173}
174
175// getPointer loads the pointer at p and returns it.
176func (p pointer) getPointer() pointer {
177 return pointer{p: *(*unsafe.Pointer)(p.p)}
178}
179
180// setPointer stores the pointer q at p.
181func (p pointer) setPointer(q pointer) {
182 *(*unsafe.Pointer)(p.p) = q.p
183}
184
185// append q to the slice pointed to by p.
186func (p pointer) appendPointer(q pointer) {
187 s := (*[]unsafe.Pointer)(p.p)
188 *s = append(*s, q.p)
189}
190
191// asPointerTo returns a reflect.Value that is a pointer to an
192// object of type t stored at p.
193func (p pointer) asPointerTo(t reflect.Type) reflect.Value {
194 return reflect.NewAt(t, p.p)
195}
196
197func atomicLoadUnmarshalInfo(p **unmarshalInfo) *unmarshalInfo {
198 return (*unmarshalInfo)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(p))))
199}
200func atomicStoreUnmarshalInfo(p **unmarshalInfo, v *unmarshalInfo) {
201 atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(p)), unsafe.Pointer(v))
202}