2012-09-22 08:52:27 -04:00
|
|
|
// Copyright 2012 The Go Authors. All rights reserved.
|
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
package reflect
|
|
|
|
|
|
|
|
|
|
// MakeRO returns a copy of v with the read-only flag set.
|
|
|
|
|
func MakeRO(v Value) Value {
|
|
|
|
|
v.flag |= flagRO
|
|
|
|
|
return v
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// IsRO reports whether v's read-only flag is set.
|
|
|
|
|
func IsRO(v Value) bool {
|
|
|
|
|
return v.flag&flagRO != 0
|
|
|
|
|
}
|
reflect: add ArrayOf, ChanOf, MapOf, SliceOf
In order to add these, we need to be able to find references
to such types that already exist in the binary. To do that, introduce
a new linker section holding a list of the types corresponding to
arrays, chans, maps, and slices.
To offset the storage cost of this list, and to simplify the code,
remove the interface{} header from the representation of a
runtime type. It was used in early versions of the code but was
made obsolete by the kind field: a switch on kind is more efficient
than a type switch.
In the godoc binary, removing the interface{} header cuts two
words from each of about 10,000 types. Adding back the list of pointers
to array, chan, map, and slice types reintroduces one word for
each of about 500 types. On a 64-bit machine, then, this CL *removes*
a net 156 kB of read-only data from the binary.
This CL does not include the needed support for precise garbage
collection. I have created issue 4375 to track that.
This CL also does not set the 'algorithm' - specifically the equality
and copy functions - for a new array correctly, so I have unexported
ArrayOf for now. That is also part of issue 4375.
Fixes #2339.
R=r, remyoudompheng, mirtchovski, iant
CC=golang-dev
https://golang.org/cl/6572043
2012-11-13 13:06:29 -05:00
|
|
|
|
reflect, runtime: fix crash in GC due to reflect.call + precise GC
Given
type Outer struct {
*Inner
...
}
the compiler generates the implementation of (*Outer).M dispatching to
the embedded Inner. The implementation is logically:
func (p *Outer) M() {
(p.Inner).M()
}
but since the only change here is the replacement of one pointer
receiver with another, the actual generated code overwrites the
original receiver with the p.Inner pointer and then jumps to the M
method expecting the *Inner receiver.
During reflect.Value.Call, we create an argument frame and the
associated data structures to describe it to the garbage collector,
populate the frame, call reflect.call to run a function call using
that frame, and then copy the results back out of the frame. The
reflect.call function does a memmove of the frame structure onto the
stack (to set up the inputs), runs the call, and the memmoves the
stack back to the frame structure (to preserve the outputs).
Originally reflect.call did not distinguish inputs from outputs: both
memmoves were for the full stack frame. However, in the case where the
called function was one of these wrappers, the rewritten receiver is
almost certainly a different type than the original receiver. This is
not a problem on the stack, where we use the program counter to
determine the type information and understand that during (*Outer).M
the receiver is an *Outer while during (*Inner).M the receiver in the
same memory word is now an *Inner. But in the statically typed
argument frame created by reflect, the receiver is always an *Outer.
Copying the modified receiver pointer off the stack into the frame
will store an *Inner there, and then if a garbage collection happens
to scan that argument frame before it is discarded, it will scan the
*Inner memory as if it were an *Outer. If the two have different
memory layouts, the collection will intepret the memory incorrectly.
Fix by only copying back the results.
Fixes #7725.
LGTM=khr
R=khr
CC=dave, golang-codereviews
https://golang.org/cl/85180043
2014-04-08 11:11:35 -04:00
|
|
|
var CallGC = &callGC
|
2014-12-01 07:52:09 -08:00
|
|
|
|
|
|
|
|
const PtrSize = ptrSize
|
|
|
|
|
const BitsPointer = bitsPointer
|
|
|
|
|
const BitsScalar = bitsScalar
|
|
|
|
|
|
2014-12-23 10:57:37 -08:00
|
|
|
func FuncLayout(t Type, rcvr Type) (frametype Type, argSize, retOffset uintptr, stack []byte, gc []byte, ptrs bool) {
|
2014-12-01 07:52:09 -08:00
|
|
|
var ft *rtype
|
|
|
|
|
var s *bitVector
|
|
|
|
|
if rcvr != nil {
|
2014-12-22 22:31:55 +03:00
|
|
|
ft, argSize, retOffset, s, _ = funcLayout(t.(*rtype), rcvr.(*rtype))
|
2014-12-01 07:52:09 -08:00
|
|
|
} else {
|
2014-12-22 22:31:55 +03:00
|
|
|
ft, argSize, retOffset, s, _ = funcLayout(t.(*rtype), nil)
|
2014-12-01 07:52:09 -08:00
|
|
|
}
|
|
|
|
|
frametype = ft
|
|
|
|
|
for i := uint32(0); i < s.n; i += 2 {
|
|
|
|
|
stack = append(stack, s.data[i/8]>>(i%8)&3)
|
|
|
|
|
}
|
2014-12-26 11:44:55 +09:00
|
|
|
if ft.kind&kindGCProg != 0 {
|
2014-12-23 10:57:37 -08:00
|
|
|
panic("can't handle gc programs")
|
|
|
|
|
}
|
|
|
|
|
gcdata := (*[1000]byte)(ft.gc[0])
|
|
|
|
|
for i := uintptr(0); i < ft.size/ptrSize; i++ {
|
2014-12-26 11:44:55 +09:00
|
|
|
gc = append(gc, gcdata[i/2]>>(i%2*4+2)&3)
|
2014-12-23 10:57:37 -08:00
|
|
|
}
|
2014-12-26 11:44:55 +09:00
|
|
|
ptrs = ft.kind&kindNoPointers == 0
|
2014-12-01 07:52:09 -08:00
|
|
|
return
|
|
|
|
|
}
|
2014-12-23 15:19:30 +11:00
|
|
|
|
|
|
|
|
func TypeLinks() []string {
|
|
|
|
|
var r []string
|
|
|
|
|
for _, m := range typelinks() {
|
|
|
|
|
for _, t := range m {
|
|
|
|
|
r = append(r, *t.string)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return r
|
|
|
|
|
}
|