@@ -120,10 +120,16 @@ func (v Value) pointer() unsafe.Pointer {
120
120
121
121
// packEface converts v to the empty interface.
122
122
func packEface (v Value ) any {
123
+ return * (* any )(unsafe .Pointer (& abi.EmptyInterface {
124
+ Type : v .typ (),
125
+ Data : packEfaceData (v ),
126
+ }))
127
+ }
128
+
129
+ // packEfaceData is a helper that packs the Data part of an interface,
130
+ // if v were to be stored in an interface.
131
+ func packEfaceData (v Value ) unsafe.Pointer {
123
132
t := v .typ ()
124
- // Declare e as a struct (and not pointer to struct) to help escape analysis.
125
- e := abi.EmptyInterface {}
126
- // First, fill in the data portion of the interface.
127
133
switch {
128
134
case ! t .IsDirectIface ():
129
135
if v .flag & flagIndir == 0 {
@@ -136,18 +142,15 @@ func packEface(v Value) any {
136
142
typedmemmove (t , c , ptr )
137
143
ptr = c
138
144
}
139
- e . Data = ptr
145
+ return ptr
140
146
case v .flag & flagIndir != 0 :
141
147
// Value is indirect, but interface is direct. We need
142
148
// to load the data at v.ptr into the interface data word.
143
- e . Data = * (* unsafe .Pointer )(v .ptr )
149
+ return * (* unsafe .Pointer )(v .ptr )
144
150
default :
145
151
// Value is direct, and so is the interface.
146
- e . Data = v .ptr
152
+ return v .ptr
147
153
}
148
- // Now, fill in the type portion.
149
- e .Type = t
150
- return * (* any )(unsafe .Pointer (& e ))
151
154
}
152
155
153
156
// unpackEface converts the empty interface i to a Value.
@@ -1544,8 +1547,18 @@ func TypeAssert[T any](v Value) (T, bool) {
1544
1547
// TypeAssert[any](ValueOf(1)) == ValueOf(1).Interface().(any)
1545
1548
// TypeAssert[error](ValueOf(&someError{})) == ValueOf(&someError{}).Interface().(error)
1546
1549
if typ .Kind () == abi .Interface {
1547
- v , ok := packEface (v ).(T )
1548
- return v , ok
1550
+ // To avoid allocating memory, in case the type assertion fails,
1551
+ // first do the type assertion with a nil Data pointer.
1552
+ iface := * (* any )(unsafe .Pointer (& abi.EmptyInterface {Type : v .typ (), Data : nil }))
1553
+ if out , ok := iface .(T ); ok {
1554
+ // Now populate the Data field properly, we update the Data ptr
1555
+ // directly to avoid an additional type asertion. We can re-use the
1556
+ // itab we already got from the runtime (through the previous type assertion).
1557
+ (* abi .CommonInterface )(unsafe .Pointer (& out )).Data = packEfaceData (v )
1558
+ return out , true
1559
+ }
1560
+ var zero T
1561
+ return zero , false
1549
1562
}
1550
1563
1551
1564
// Both v and T must be concrete types.
0 commit comments