David K. Bainbridge | e05cf0c | 2021-08-19 03:16:50 +0000 | [diff] [blame] | 1 | // Copyright 2018 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,!appengine |
| 6 | |
| 7 | package protoreflect |
| 8 | |
| 9 | import ( |
| 10 | "unsafe" |
| 11 | |
| 12 | "google.golang.org/protobuf/internal/pragma" |
| 13 | ) |
| 14 | |
| 15 | type ( |
| 16 | stringHeader struct { |
| 17 | Data unsafe.Pointer |
| 18 | Len int |
| 19 | } |
| 20 | sliceHeader struct { |
| 21 | Data unsafe.Pointer |
| 22 | Len int |
| 23 | Cap int |
| 24 | } |
| 25 | ifaceHeader struct { |
| 26 | Type unsafe.Pointer |
| 27 | Data unsafe.Pointer |
| 28 | } |
| 29 | ) |
| 30 | |
| 31 | var ( |
| 32 | nilType = typeOf(nil) |
| 33 | boolType = typeOf(*new(bool)) |
| 34 | int32Type = typeOf(*new(int32)) |
| 35 | int64Type = typeOf(*new(int64)) |
| 36 | uint32Type = typeOf(*new(uint32)) |
| 37 | uint64Type = typeOf(*new(uint64)) |
| 38 | float32Type = typeOf(*new(float32)) |
| 39 | float64Type = typeOf(*new(float64)) |
| 40 | stringType = typeOf(*new(string)) |
| 41 | bytesType = typeOf(*new([]byte)) |
| 42 | enumType = typeOf(*new(EnumNumber)) |
| 43 | ) |
| 44 | |
| 45 | // typeOf returns a pointer to the Go type information. |
| 46 | // The pointer is comparable and equal if and only if the types are identical. |
| 47 | func typeOf(t interface{}) unsafe.Pointer { |
| 48 | return (*ifaceHeader)(unsafe.Pointer(&t)).Type |
| 49 | } |
| 50 | |
| 51 | // value is a union where only one type can be represented at a time. |
| 52 | // The struct is 24B large on 64-bit systems and requires the minimum storage |
| 53 | // necessary to represent each possible type. |
| 54 | // |
| 55 | // The Go GC needs to be able to scan variables containing pointers. |
| 56 | // As such, pointers and non-pointers cannot be intermixed. |
| 57 | type value struct { |
| 58 | pragma.DoNotCompare // 0B |
| 59 | |
| 60 | // typ stores the type of the value as a pointer to the Go type. |
| 61 | typ unsafe.Pointer // 8B |
| 62 | |
| 63 | // ptr stores the data pointer for a String, Bytes, or interface value. |
| 64 | ptr unsafe.Pointer // 8B |
| 65 | |
| 66 | // num stores a Bool, Int32, Int64, Uint32, Uint64, Float32, Float64, or |
| 67 | // Enum value as a raw uint64. |
| 68 | // |
| 69 | // It is also used to store the length of a String or Bytes value; |
| 70 | // the capacity is ignored. |
| 71 | num uint64 // 8B |
| 72 | } |
| 73 | |
| 74 | func valueOfString(v string) Value { |
| 75 | p := (*stringHeader)(unsafe.Pointer(&v)) |
| 76 | return Value{typ: stringType, ptr: p.Data, num: uint64(len(v))} |
| 77 | } |
| 78 | func valueOfBytes(v []byte) Value { |
| 79 | p := (*sliceHeader)(unsafe.Pointer(&v)) |
| 80 | return Value{typ: bytesType, ptr: p.Data, num: uint64(len(v))} |
| 81 | } |
| 82 | func valueOfIface(v interface{}) Value { |
| 83 | p := (*ifaceHeader)(unsafe.Pointer(&v)) |
| 84 | return Value{typ: p.Type, ptr: p.Data} |
| 85 | } |
| 86 | |
| 87 | func (v Value) getString() (x string) { |
| 88 | *(*stringHeader)(unsafe.Pointer(&x)) = stringHeader{Data: v.ptr, Len: int(v.num)} |
| 89 | return x |
| 90 | } |
| 91 | func (v Value) getBytes() (x []byte) { |
| 92 | *(*sliceHeader)(unsafe.Pointer(&x)) = sliceHeader{Data: v.ptr, Len: int(v.num), Cap: int(v.num)} |
| 93 | return x |
| 94 | } |
| 95 | func (v Value) getIface() (x interface{}) { |
| 96 | *(*ifaceHeader)(unsafe.Pointer(&x)) = ifaceHeader{Type: v.typ, Data: v.ptr} |
| 97 | return x |
| 98 | } |