Left: | ||
Right: |
OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2012 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 // MakeFunc implementation. | |
6 | |
7 package reflect | |
8 | |
9 import ( | |
10 "runtime" | |
11 "unsafe" | |
12 ) | |
13 | |
14 // makeFuncImpl is the closure value implementing the function | |
15 // returned by MakeFunc. | |
16 type makeFuncImpl struct { | |
17 // References visible to the garbage collector. | |
18 // The code holds the same references. | |
19 typ *commonType | |
20 fn func([]Value) []Value | |
21 | |
22 // code is the actual machine code invoked for the function. | |
23 code [40]byte | |
24 } | |
25 | |
26 // MakeFunc creates and returns a function of the given type. | |
27 // When called, that function converts its arguments to Values, | |
28 // invokes fn, and then converts fn's result Values into the | |
29 // results returned to the caller. | |
30 func MakeFunc(typ Type, fn func([]Value) []Value) Value { | |
r
2012/09/23 05:56:08
i think the type
func([]Value) []Value
should be g
rsc
2012/09/23 17:51:53
While I see the documentation benefit, this would
| |
31 if typ.Kind() != Func { | |
32 panic("reflect: call of MakeFunc with non-Func type") | |
33 } | |
34 | |
35 // Gather type pointer and function pointers | |
36 // for use in hand-assembled closure. | |
37 t := typ.common() | |
38 | |
39 // Create function impl. | |
40 // We don't need to save a pointer to makeFuncStub, because it is in | |
41 // the text segment and cannot be garbage collected. | |
42 impl := &makeFuncImpl{ | |
43 typ: t, | |
44 fn: fn, | |
45 } | |
46 | |
47 tptr := unsafe.Pointer(t) | |
48 fptr := *(*unsafe.Pointer)(unsafe.Pointer(&fn)) | |
49 tmp := makeFuncStub | |
50 stub := *(*unsafe.Pointer)(unsafe.Pointer(&tmp)) | |
51 | |
52 // Create code. Copy template and fill in pointer values. | |
53 switch runtime.GOARCH { | |
54 case "amd64": | |
55 copy(impl.code[:], amd64CallStub) | |
56 *(*unsafe.Pointer)(unsafe.Pointer(&impl.code[2])) = tptr | |
57 *(*unsafe.Pointer)(unsafe.Pointer(&impl.code[12])) = fptr | |
58 *(*unsafe.Pointer)(unsafe.Pointer(&impl.code[22])) = stub | |
59 | |
60 case "386": | |
61 copy(impl.code[:], _386CallStub) | |
62 *(*unsafe.Pointer)(unsafe.Pointer(&impl.code[1])) = tptr | |
63 *(*unsafe.Pointer)(unsafe.Pointer(&impl.code[6])) = fptr | |
64 *(*unsafe.Pointer)(unsafe.Pointer(&impl.code[11])) = stub | |
65 | |
66 case "arm": | |
67 code := (*[10]uintptr)(unsafe.Pointer(&impl.code[0])) | |
68 copy(code[:], armCallStub) | |
69 code[len(armCallStub)] = uintptr(tptr) | |
70 code[len(armCallStub)+1] = uintptr(fptr) | |
71 code[len(armCallStub)+2] = uintptr(stub) | |
72 | |
73 cacheflush(&impl.code[0], &impl.code[len(impl.code)-1]) | |
74 } | |
iant
2012/09/23 05:10:54
default:
panic("forgot to implement this")
rsc
2012/09/23 17:51:53
Done.
| |
75 | |
76 return Value{t, unsafe.Pointer(&impl.code[0]), flag(Func) << flagKindShi ft} | |
77 } | |
78 | |
79 func cacheflush(start, end *byte) | |
80 | |
81 // makeFuncStub is an assembly function used by the code generated | |
82 // and returned from MakeFunc. The code returned from makeFunc | |
83 // does, schematically, | |
84 // | |
85 // MOV $typ, R0 | |
86 // MOV $fn, R1 | |
87 // MOV $0(FP), R2 | |
88 // JMP makeFuncStub | |
89 // | |
90 // That is, it copies the type and function pointer passed to MakeFunc | |
91 // into the first two machine registers and then copies the argument frame | |
92 // pointer into the third. Then it jumps to makeFuncStub, which calls callReflec t | |
93 // with those arguments. Using a jmp to makeFuncStub instead of making the | |
94 // call directly keeps the allocated code simpler but, perhaps more | |
95 // importantly, also keeps the allocated PCs off the call stack. | |
96 // Nothing ever returns to the allocated code. | |
97 func makeFuncStub() | |
98 | |
99 // amd64CallStub is the MakeFunc code template for amd64 machines. | |
100 var amd64CallStub = []byte{ | |
101 // MOVQ $constant, AX | |
102 0x48, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
103 // MOVQ $constant, BX | |
104 0x48, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
105 // MOVQ $constant, DX | |
106 0x48, 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
107 // LEAQ 8(SP), CX (argument frame) | |
108 0x48, 0x8d, 0x4c, 0x24, 0x08, | |
109 // JMP *DX | |
110 0xff, 0xe2, | |
111 } | |
112 | |
113 // _386CallStub is the MakeFunc code template for 386 machines. | |
114 var _386CallStub = []byte{ | |
115 // MOVL $constant, AX | |
116 0xb8, 0x00, 0x00, 0x00, 0x00, | |
117 // MOVL $constant, BX | |
118 0xbb, 0x00, 0x00, 0x00, 0x00, | |
119 // MOVL $constant, DX | |
120 0xba, 0x00, 0x00, 0x00, 0x00, | |
121 // LEAL 4(SP), CX (argument frame) | |
122 0x8d, 0x4c, 0x24, 0x04, | |
123 // JMP *DX | |
124 0xff, 0xe2, | |
125 } | |
126 | |
127 // armCallStub is the MakeFunc code template for arm machines. | |
128 var armCallStub = []uintptr{ | |
129 0xe59f000c, // MOVW 0x14(PC), R0 | |
130 0xe59f100c, // MOVW 0x14(PC), R1 | |
131 0xe28d2004, // MOVW $4(SP), R2 | |
iant
2012/09/23 05:10:54
Is MOVW $4(SP), R2 really the 5a mnemonic for this
rsc
2012/09/23 17:51:53
It is certainly a valid one; I don't know if it is
| |
132 0xe59ff008, // MOVW 0x10(PC), PC | |
133 0xeafffffe, // B 0(PC), just in case | |
134 } | |
OLD | NEW |