]> Cypherpunks repositories - gostls13.git/commitdiff
reflect: stop using run-time code generation
authorRuss Cox <rsc@golang.org>
Fri, 22 Feb 2013 20:23:57 +0000 (15:23 -0500)
committerRuss Cox <rsc@golang.org>
Fri, 22 Feb 2013 20:23:57 +0000 (15:23 -0500)
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

src/pkg/reflect/asm_386.s
src/pkg/reflect/asm_amd64.s
src/pkg/reflect/asm_arm.s
src/pkg/reflect/makefunc.go
src/pkg/reflect/value.go

index 30ff3413acbda78fc3d4b677bc4feee7833a4e1f..27d3fa21d505ed179539d568022d08ff85a88666 100644 (file)
@@ -2,17 +2,12 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// makeFuncStub is jumped to by the code generated by MakeFunc.
-// The code sets AX = type, BX = fn, CX = frame before the jump.
+// makeFuncStub is the code half of the function returned by MakeFunc.
 // See the comment on the declaration of makeFuncStub in value.go
 // for more details.
-TEXT ·makeFuncStub(SB),7,$12
-       MOVL    AX, 0(SP)
-       MOVL    BX, 4(SP)
-       MOVL    CX, 8(SP)
+TEXT ·makeFuncStub(SB),7,$8
+       MOVL    DX, 0(SP)
+       LEAL    arg+0(FP), CX
+       MOVL    CX, 4(SP)
        CALL    ·callReflect(SB)
        RET
-
-// unused
-TEXT ·cacheflush(SB),7,$0
-       RET
index ce33e78c24e85015c1aecf1b2ad9ad286a91ce78..d51d982a9d909f9f80312e8de7e0532f8dee07ae 100644 (file)
@@ -2,17 +2,12 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// makeFuncStub is jumped to by the code generated by MakeFunc.
-// The code sets AX = type, BX = fn, CX = frame before the jump.
+// makeFuncStub is the code half of the function returned by MakeFunc.
 // See the comment on the declaration of makeFuncStub in value.go
 // for more details.
-TEXT ·makeFuncStub(SB),7,$24
-       MOVQ    AX, 0(SP)
-       MOVQ    BX, 8(SP)
-       MOVQ    CX, 16(SP)
+TEXT ·makeFuncStub(SB),7,$16
+       MOVQ    DX, 0(SP)
+       LEAQ    arg+0(FP), CX
+       MOVQ    CX, 8(SP)
        CALL    ·callReflect(SB)
        RET
-
-// unused
-TEXT ·cacheflush(SB),7,$0
-       RET
index 3f1814cf065c3ade7a9d77667c881492e56e0c4d..db487f8a56e037bfa7723ee6c5b62bae56ec93cd 100644 (file)
@@ -3,15 +3,11 @@
 // license that can be found in the LICENSE file.
 
 // 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
 // for more details.
-TEXT ·makeFuncStub(SB),7,$12
-       MOVW    R0, 4(R13)
+TEXT ·makeFuncStub(SB),7,$8
+       MOVW    R7, 4(R13)
+       MOVW    $arg+0(FP), R1
        MOVW    R1, 8(R13)
-       MOVW    R2, 12(R13)
        BL      ·callReflect(SB)
        RET
-
-TEXT ·cacheflush(SB),7,$-4
-       B       runtime·cacheflush(SB)
index e85a1f3b0e3aafb3c2d879b0c5ce6d57fdca629a..024f938f1da7eab69d781cc8afa7b6286108d440 100644 (file)
@@ -7,23 +7,15 @@
 package reflect
 
 import (
-       "runtime"
        "unsafe"
 )
 
 // makeFuncImpl is the closure value implementing the function
 // returned by MakeFunc.
 type makeFuncImpl struct {
-       codeptr unsafe.Pointer
-
-       // 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
-
-       // code is the actual machine code invoked for the closure.
-       code [40]byte
+       code uintptr
+       typ  *funcType
+       fn   func([]Value) []Value
 }
 
 // MakeFunc returns a new function of the given Type
@@ -53,107 +45,23 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
                panic("reflect: call of MakeFunc with non-Func type")
        }
 
-       // Gather type pointer and function pointers
-       // for use in hand-assembled closure.
        t := typ.common()
+       ftyp := (*funcType)(unsafe.Pointer(t))
 
-       // Create function impl.
-       // We don't need to save a pointer to makeFuncStub, because it is in
-       // the text segment and cannot be garbage collected.
-       impl := &makeFuncImpl{
-               typ: t,
-               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)
+       // indirect Go func value (dummy) to obtain
+       // actual code address. (A Go func is a pointer
+       // to a C function pointer. http://golang.org/s/go11func.)
+       dummy := makeFuncStub
+       code := **(**uintptr)(unsafe.Pointer(&dummy))
 
-       case "amd64":
-               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])
-       }
+       impl := &makeFuncImpl{code: code, typ: ftyp, fn: fn}
 
        return Value{t, unsafe.Pointer(impl), flag(Func) << flagKindShift}
 }
 
-func cacheflush(start, end *byte)
-
-// makeFuncStub is an assembly function used by the code generated
-// and returned from MakeFunc. The code returned from makeFunc
-// does, schematically,
-//
-//     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.
+// makeFuncStub is an assembly function that is the code half of
+// the function returned from MakeFunc. It expects a *callReflectFunc
+// as its context register, and its job is to invoke callReflect(ctxt, frame)
+// where ctxt is the context register and frame is a pointer to the first
+// word in the passed-in argument frame.
 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
-}
index 11659751d16ea270256ea38a3350a888d6838109..c87812c469669cb662604a46567e9281a0ef19fb 100644 (file)
@@ -555,7 +555,10 @@ func (v Value) call(method string, in []Value) []Value {
 // frame into a call using Values.
 // 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.
-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.
        ptr := frame
        off := uintptr(0)