| // Copyright 2013 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. |
| |
| // MakeFunc 386 implementation. |
| |
| package reflect |
| |
| import "unsafe" |
| |
| // The assembler stub will pass a pointer to this structure. We |
| // assume that no parameters are passed in registers--that is, we do |
| // not support the -mregparm option. On return we will set the |
| // registers that might hold result values. |
| type i386Regs struct { |
| esp uint32 |
| eax uint32 // Value to return in %eax. |
| st0 uint64 // Value to return in %st(0). |
| } |
| |
| // MakeFuncStubGo implements the 386 calling convention for MakeFunc. |
| // This should not be called. It is exported so that assembly code |
| // can call it. |
| |
| func MakeFuncStubGo(regs *i386Regs, c *makeFuncImpl) { |
| ftyp := c.typ |
| |
| // See if the result requires a struct. If it does, the first |
| // parameter is a pointer to the struct. |
| retStruct := false |
| retEmpty := false |
| switch len(ftyp.out) { |
| case 0: |
| retEmpty = true |
| case 1: |
| if ftyp.out[0].size == 0 { |
| retEmpty = true |
| } else { |
| switch ftyp.out[0].Kind() { |
| case Complex64, Complex128, Array, Interface, Slice, String, Struct: |
| retStruct = true |
| } |
| } |
| default: |
| size := uintptr(0) |
| for _, typ := range ftyp.out { |
| size += typ.size |
| } |
| if size == 0 { |
| retEmpty = true |
| } else { |
| retStruct = true |
| } |
| } |
| |
| in := make([]Value, 0, len(ftyp.in)) |
| ap := uintptr(regs.esp) |
| |
| var retPtr unsafe.Pointer |
| if retStruct { |
| retPtr = *(*unsafe.Pointer)(unsafe.Pointer(ap)) |
| ap += ptrSize |
| } |
| |
| for _, rt := range ftyp.in { |
| ap = align(ap, ptrSize) |
| |
| // We have to copy the argument onto the heap in case |
| // the function hangs on the reflect.Value we pass it. |
| p := unsafe_New(rt) |
| memmove(p, unsafe.Pointer(ap), rt.size) |
| |
| v := Value{rt, p, flag(rt.Kind()<<flagKindShift) | flagIndir} |
| in = append(in, v) |
| ap += rt.size |
| } |
| |
| // Call the real function. |
| |
| out := c.fn(in) |
| |
| if len(out) != len(ftyp.out) { |
| panic("reflect: wrong return count from function created by MakeFunc") |
| } |
| |
| for i, typ := range ftyp.out { |
| v := out[i] |
| if v.typ != typ { |
| panic("reflect: function created by MakeFunc using " + funcName(c.fn) + |
| " returned wrong type: have " + |
| out[i].typ.String() + " for " + typ.String()) |
| } |
| if v.flag&flagRO != 0 { |
| panic("reflect: function created by MakeFunc using " + funcName(c.fn) + |
| " returned value obtained from unexported field") |
| } |
| } |
| |
| if retEmpty { |
| return |
| } |
| |
| if retStruct { |
| off := uintptr(0) |
| for i, typ := range ftyp.out { |
| v := out[i] |
| off = align(off, uintptr(typ.fieldAlign)) |
| addr := unsafe.Pointer(uintptr(retPtr) + off) |
| if v.flag&flagIndir == 0 && (v.kind() == Ptr || v.kind() == UnsafePointer) { |
| storeIword(addr, iword(v.val), typ.size) |
| } else { |
| memmove(addr, v.val, typ.size) |
| } |
| off += typ.size |
| } |
| regs.eax = uint32(uintptr(retPtr)) |
| return |
| } |
| |
| if len(ftyp.out) != 1 { |
| panic("inconsistency") |
| } |
| |
| v := out[0] |
| w := v.iword() |
| if v.Kind() != Ptr && v.Kind() != UnsafePointer { |
| w = loadIword(unsafe.Pointer(w), v.typ.size) |
| } |
| switch v.Kind() { |
| case Float32, Float64: |
| regs.st0 = uint64(uintptr(w)) |
| default: |
| regs.eax = uint32(uintptr(w)) |
| } |
| } |