Commit b1b67a36 authored by Russ Cox's avatar Russ Cox

reflect: stop using run-time code generation

Step 3 of http://golang.org/s/go11func.

Fixes #3736.
Fixes #3738.
Fixes #4081.

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/7393050
parent 18eb3cfd
...@@ -2,17 +2,12 @@ ...@@ -2,17 +2,12 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// makeFuncStub is jumped to by the code generated by MakeFunc. // makeFuncStub is the code half of the function returned by MakeFunc.
// The code sets AX = type, BX = fn, CX = frame before the jump.
// See the comment on the declaration of makeFuncStub in value.go // See the comment on the declaration of makeFuncStub in value.go
// for more details. // for more details.
TEXT ·makeFuncStub(SB),7,$12 TEXT ·makeFuncStub(SB),7,$8
MOVL AX, 0(SP) MOVL DX, 0(SP)
MOVL BX, 4(SP) LEAL arg+0(FP), CX
MOVL CX, 8(SP) MOVL CX, 4(SP)
CALL ·callReflect(SB) CALL ·callReflect(SB)
RET RET
// unused
TEXT ·cacheflush(SB),7,$0
RET
...@@ -2,17 +2,12 @@ ...@@ -2,17 +2,12 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// makeFuncStub is jumped to by the code generated by MakeFunc. // makeFuncStub is the code half of the function returned by MakeFunc.
// The code sets AX = type, BX = fn, CX = frame before the jump.
// See the comment on the declaration of makeFuncStub in value.go // See the comment on the declaration of makeFuncStub in value.go
// for more details. // for more details.
TEXT ·makeFuncStub(SB),7,$24 TEXT ·makeFuncStub(SB),7,$16
MOVQ AX, 0(SP) MOVQ DX, 0(SP)
MOVQ BX, 8(SP) LEAQ arg+0(FP), CX
MOVQ CX, 16(SP) MOVQ CX, 8(SP)
CALL ·callReflect(SB) CALL ·callReflect(SB)
RET RET
// unused
TEXT ·cacheflush(SB),7,$0
RET
...@@ -3,15 +3,11 @@ ...@@ -3,15 +3,11 @@
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// makeFuncStub is jumped to by the code generated by MakeFunc. // makeFuncStub is jumped to by the code generated by MakeFunc.
// The code sets R0 = type, R1 = fn, R2 = frame before the jump.
// See the comment on the declaration of makeFuncStub in value.go // See the comment on the declaration of makeFuncStub in value.go
// for more details. // for more details.
TEXT ·makeFuncStub(SB),7,$12 TEXT ·makeFuncStub(SB),7,$8
MOVW R0, 4(R13) MOVW R7, 4(R13)
MOVW $arg+0(FP), R1
MOVW R1, 8(R13) MOVW R1, 8(R13)
MOVW R2, 12(R13)
BL ·callReflect(SB) BL ·callReflect(SB)
RET RET
TEXT ·cacheflush(SB),7,$-4
B runtime·cacheflush(SB)
...@@ -7,23 +7,15 @@ ...@@ -7,23 +7,15 @@
package reflect package reflect
import ( import (
"runtime"
"unsafe" "unsafe"
) )
// makeFuncImpl is the closure value implementing the function // makeFuncImpl is the closure value implementing the function
// returned by MakeFunc. // returned by MakeFunc.
type makeFuncImpl struct { type makeFuncImpl struct {
codeptr unsafe.Pointer code uintptr
typ *funcType
// References visible to the garbage collector.
// The code array below contains the same references
// embedded in the machine code.
typ *rtype
fn func([]Value) []Value fn func([]Value) []Value
// code is the actual machine code invoked for the closure.
code [40]byte
} }
// MakeFunc returns a new function of the given Type // MakeFunc returns a new function of the given Type
...@@ -53,107 +45,23 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value { ...@@ -53,107 +45,23 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
panic("reflect: call of MakeFunc with non-Func type") panic("reflect: call of MakeFunc with non-Func type")
} }
// Gather type pointer and function pointers
// for use in hand-assembled closure.
t := typ.common() t := typ.common()
ftyp := (*funcType)(unsafe.Pointer(t))
// Create function impl. // indirect Go func value (dummy) to obtain
// We don't need to save a pointer to makeFuncStub, because it is in // actual code address. (A Go func is a pointer
// the text segment and cannot be garbage collected. // to a C function pointer. http://golang.org/s/go11func.)
impl := &makeFuncImpl{ dummy := makeFuncStub
typ: t, code := **(**uintptr)(unsafe.Pointer(&dummy))
fn: fn,
}
impl.codeptr = unsafe.Pointer(&impl.code[0])
tptr := unsafe.Pointer(t)
fptr := *(*unsafe.Pointer)(unsafe.Pointer(&fn))
tmp := makeFuncStub
stub := **(**unsafe.Pointer)(unsafe.Pointer(&tmp))
// Create code. Copy template and fill in pointer values.
switch runtime.GOARCH {
default:
panic("reflect.MakeFunc: unexpected GOARCH: " + runtime.GOARCH)
case "amd64": impl := &makeFuncImpl{code: code, typ: ftyp, fn: fn}
copy(impl.code[:], amd64CallStub)
*(*unsafe.Pointer)(unsafe.Pointer(&impl.code[2])) = tptr
*(*unsafe.Pointer)(unsafe.Pointer(&impl.code[12])) = fptr
*(*unsafe.Pointer)(unsafe.Pointer(&impl.code[22])) = stub
case "386":
copy(impl.code[:], _386CallStub)
*(*unsafe.Pointer)(unsafe.Pointer(&impl.code[1])) = tptr
*(*unsafe.Pointer)(unsafe.Pointer(&impl.code[6])) = fptr
*(*unsafe.Pointer)(unsafe.Pointer(&impl.code[11])) = stub
case "arm":
code := (*[10]uintptr)(unsafe.Pointer(&impl.code[0]))
copy(code[:], armCallStub)
code[len(armCallStub)] = uintptr(tptr)
code[len(armCallStub)+1] = uintptr(fptr)
code[len(armCallStub)+2] = uintptr(stub)
cacheflush(&impl.code[0], &impl.code[len(impl.code)-1])
}
return Value{t, unsafe.Pointer(impl), flag(Func) << flagKindShift} return Value{t, unsafe.Pointer(impl), flag(Func) << flagKindShift}
} }
func cacheflush(start, end *byte) // makeFuncStub is an assembly function that is the code half of
// the function returned from MakeFunc. It expects a *callReflectFunc
// makeFuncStub is an assembly function used by the code generated // as its context register, and its job is to invoke callReflect(ctxt, frame)
// and returned from MakeFunc. The code returned from makeFunc // where ctxt is the context register and frame is a pointer to the first
// does, schematically, // word in the passed-in argument frame.
//
// MOV $typ, R0
// MOV $fn, R1
// MOV $0(FP), R2
// JMP makeFuncStub
//
// That is, it copies the type and function pointer passed to MakeFunc
// into the first two machine registers and then copies the argument frame
// pointer into the third. Then it jumps to makeFuncStub, which calls callReflect
// with those arguments. Using a jmp to makeFuncStub instead of making the
// call directly keeps the allocated code simpler but, perhaps more
// importantly, also keeps the allocated PCs off the call stack.
// Nothing ever returns to the allocated code.
func makeFuncStub() func makeFuncStub()
// amd64CallStub is the MakeFunc code template for amd64 machines.
var amd64CallStub = []byte{
// MOVQ $constant, AX
0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// MOVQ $constant, BX
0x48, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// MOVQ $constant, DX
0x48, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// LEAQ 8(SP), CX (argument frame)
0x48, 0x8d, 0x4c, 0x24, 0x08,
// JMP *DX
0xff, 0xe2,
}
// _386CallStub is the MakeFunc code template for 386 machines.
var _386CallStub = []byte{
// MOVL $constant, AX
0xb8, 0x00, 0x00, 0x00, 0x00,
// MOVL $constant, BX
0xbb, 0x00, 0x00, 0x00, 0x00,
// MOVL $constant, DX
0xba, 0x00, 0x00, 0x00, 0x00,
// LEAL 4(SP), CX (argument frame)
0x8d, 0x4c, 0x24, 0x04,
// JMP *DX
0xff, 0xe2,
}
// armCallStub is the MakeFunc code template for arm machines.
var armCallStub = []uintptr{
0xe59f000c, // MOVW 0x14(PC), R0
0xe59f100c, // MOVW 0x14(PC), R1
0xe28d2004, // MOVW $4(SP), R2
0xe59ff008, // MOVW 0x10(PC), PC
0xeafffffe, // B 0(PC), just in case
}
...@@ -555,7 +555,10 @@ func (v Value) call(method string, in []Value) []Value { ...@@ -555,7 +555,10 @@ func (v Value) call(method string, in []Value) []Value {
// frame into a call using Values. // frame into a call using Values.
// It is in this file so that it can be next to the call method above. // It is in this file so that it can be next to the call method above.
// The remainder of the MakeFunc implementation is in makefunc.go. // The remainder of the MakeFunc implementation is in makefunc.go.
func callReflect(ftyp *funcType, f func([]Value) []Value, frame unsafe.Pointer) { func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
ftyp := ctxt.typ
f := ctxt.fn
// Copy argument frame into Values. // Copy argument frame into Values.
ptr := frame ptr := frame
off := uintptr(0) off := uintptr(0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment