From e6de8401bf11187174e514361b6e7fde1267b98e Mon Sep 17 00:00:00 2001 From: visualfc Date: Tue, 5 Nov 2024 16:06:18 +0800 Subject: [PATCH] internal/lib/reflect: makeMethodValue --- cl/_testgo/reflect/in.go | 18 +++++++- cl/_testgo/reflect/out.ll | 62 ++++++++++++++++++++++++++++ internal/lib/reflect/makefunc.go | 70 ++++++++++++++++---------------- 3 files changed, 115 insertions(+), 35 deletions(-) diff --git a/cl/_testgo/reflect/in.go b/cl/_testgo/reflect/in.go index a82a83c0..72c2b7d7 100644 --- a/cl/_testgo/reflect/in.go +++ b/cl/_testgo/reflect/in.go @@ -1,6 +1,9 @@ package main -import "reflect" +import ( + "reflect" + "unsafe" +) func main() { callFunc() @@ -56,6 +59,11 @@ type I interface { Add(n int) int } +type abi struct { + typ unsafe.Pointer + data unsafe.Pointer +} + func callMethod() { t := &T{1} v := reflect.ValueOf(t) @@ -63,11 +71,15 @@ func callMethod() { println("method", fn.Kind(), fn.Type().String()) r := fn.Call([]reflect.Value{reflect.ValueOf(100)}) println(r[0].Int()) + //TODO type assert // ifn, ok := fn.Interface().(func(int) int) // if !ok { // panic("error") // } // ifn(1) + v2 := reflect.ValueOf(fn.Interface()) + r2 := v2.Call([]reflect.Value{reflect.ValueOf(100)}) + println(r2[0].Int()) } func callIMethod() { @@ -77,9 +89,13 @@ func callIMethod() { println("imethod", fn.Kind(), fn.Type().String()) r := fn.Call([]reflect.Value{reflect.ValueOf(100)}) println(r[0].Int()) + //TODO type assert // ifn, ok := fn.Interface().(func(int) int) // if !ok { // panic("error") // } // ifn(1) + v2 := reflect.ValueOf(fn.Interface()) + r2 := v2.Call([]reflect.Value{reflect.ValueOf(100)}) + println(r2[0].Int()) } diff --git a/cl/_testgo/reflect/out.ll b/cl/_testgo/reflect/out.ll index 45346867..8da35241 100644 --- a/cl/_testgo/reflect/out.ll +++ b/cl/_testgo/reflect/out.ll @@ -448,6 +448,37 @@ _llgo_0: %55 = call i64 @reflect.Value.Int(%reflect.Value %54) call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %55) call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + %56 = call %"github.com/goplus/llgo/internal/runtime.eface" @reflect.Value.Interface(%reflect.Value %18) + %57 = call %reflect.Value @reflect.ValueOf(%"github.com/goplus/llgo/internal/runtime.eface" %56) + %58 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 24) + %59 = getelementptr inbounds %reflect.Value, ptr %58, i64 0 + %60 = load ptr, ptr @_llgo_int, align 8 + %61 = alloca %"github.com/goplus/llgo/internal/runtime.eface", align 8 + %62 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %61, i32 0, i32 0 + store ptr %60, ptr %62, align 8 + %63 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %61, i32 0, i32 1 + store ptr inttoptr (i64 100 to ptr), ptr %63, align 8 + %64 = load %"github.com/goplus/llgo/internal/runtime.eface", ptr %61, align 8 + %65 = call %reflect.Value @reflect.ValueOf(%"github.com/goplus/llgo/internal/runtime.eface" %64) + store %reflect.Value %65, ptr %59, align 8 + %66 = alloca %"github.com/goplus/llgo/internal/runtime.Slice", align 8 + %67 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %66, i32 0, i32 0 + store ptr %58, ptr %67, align 8 + %68 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %66, i32 0, i32 1 + store i64 1, ptr %68, align 4 + %69 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %66, i32 0, i32 2 + store i64 1, ptr %69, align 4 + %70 = load %"github.com/goplus/llgo/internal/runtime.Slice", ptr %66, align 8 + %71 = call %"github.com/goplus/llgo/internal/runtime.Slice" @reflect.Value.Call(%reflect.Value %57, %"github.com/goplus/llgo/internal/runtime.Slice" %70) + %72 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %71, 0 + %73 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %71, 1 + %74 = icmp sge i64 0, %73 + call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %74) + %75 = getelementptr inbounds %reflect.Value, ptr %72, i64 0 + %76 = load %reflect.Value, ptr %75, align 8 + %77 = call i64 @reflect.Value.Int(%reflect.Value %76) + call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %77) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) ret void } @@ -521,6 +552,37 @@ _llgo_0: %45 = call i64 @reflect.Value.Int(%reflect.Value %44) call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %45) call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) + %46 = call %"github.com/goplus/llgo/internal/runtime.eface" @reflect.Value.Interface(%reflect.Value %8) + %47 = call %reflect.Value @reflect.ValueOf(%"github.com/goplus/llgo/internal/runtime.eface" %46) + %48 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 24) + %49 = getelementptr inbounds %reflect.Value, ptr %48, i64 0 + %50 = load ptr, ptr @_llgo_int, align 8 + %51 = alloca %"github.com/goplus/llgo/internal/runtime.eface", align 8 + %52 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %51, i32 0, i32 0 + store ptr %50, ptr %52, align 8 + %53 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.eface", ptr %51, i32 0, i32 1 + store ptr inttoptr (i64 100 to ptr), ptr %53, align 8 + %54 = load %"github.com/goplus/llgo/internal/runtime.eface", ptr %51, align 8 + %55 = call %reflect.Value @reflect.ValueOf(%"github.com/goplus/llgo/internal/runtime.eface" %54) + store %reflect.Value %55, ptr %49, align 8 + %56 = alloca %"github.com/goplus/llgo/internal/runtime.Slice", align 8 + %57 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %56, i32 0, i32 0 + store ptr %48, ptr %57, align 8 + %58 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %56, i32 0, i32 1 + store i64 1, ptr %58, align 4 + %59 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.Slice", ptr %56, i32 0, i32 2 + store i64 1, ptr %59, align 4 + %60 = load %"github.com/goplus/llgo/internal/runtime.Slice", ptr %56, align 8 + %61 = call %"github.com/goplus/llgo/internal/runtime.Slice" @reflect.Value.Call(%reflect.Value %47, %"github.com/goplus/llgo/internal/runtime.Slice" %60) + %62 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %61, 0 + %63 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %61, 1 + %64 = icmp sge i64 0, %63 + call void @"github.com/goplus/llgo/internal/runtime.AssertIndexRange"(i1 %64) + %65 = getelementptr inbounds %reflect.Value, ptr %62, i64 0 + %66 = load %reflect.Value, ptr %65, align 8 + %67 = call i64 @reflect.Value.Int(%reflect.Value %66) + call void @"github.com/goplus/llgo/internal/runtime.PrintInt"(i64 %67) + call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10) ret void } diff --git a/internal/lib/reflect/makefunc.go b/internal/lib/reflect/makefunc.go index cdc48840..ac27c725 100644 --- a/internal/lib/reflect/makefunc.go +++ b/internal/lib/reflect/makefunc.go @@ -22,6 +22,13 @@ package reflect +import ( + "unsafe" + + "github.com/goplus/llgo/internal/abi" + "github.com/goplus/llgo/internal/runtime" +) + /* import ( "unsafe" @@ -111,42 +118,37 @@ type methodValue struct { // reflect can tell, but the true func representation can be handled // by code like Convert and Interface and Assign. func makeMethodValue(op string, v Value) Value { - /* - if v.flag&flagMethod == 0 { - panic("reflect: internal error: invalid use of makeMethodValue") - } + if v.flag&flagMethod == 0 { + panic("reflect: internal error: invalid use of makeMethodValue") + } - // Ignoring the flagMethod bit, v describes the receiver, not the method type. - fl := v.flag & (flagRO | flagAddr | flagIndir) - fl |= flag(v.typ().Kind()) - rcvr := Value{v.typ(), v.ptr, fl} + // Ignoring the flagMethod bit, v describes the receiver, not the method type. + fl := v.flag & (flagRO | flagAddr | flagIndir) + fl |= flag(v.typ().Kind()) + rcvr := Value{v.typ(), v.ptr, fl} - // v.Type returns the actual type of the method value. - ftyp := (*funcType)(unsafe.Pointer(v.Type().(*rtype))) - - code := methodValueCallCodePtr() - - // methodValue contains a stack map for use by the runtime - _, _, abid := funcLayout(ftyp, nil) - fv := &methodValue{ - makeFuncCtxt: makeFuncCtxt{ - fn: code, - stack: abid.stackPtrs, - argLen: abid.stackCallArgsSize, - regPtrs: abid.inRegPtrs, - }, - method: int(v.flag) >> flagMethodShift, - rcvr: rcvr, - } - - // Cause panic if method is not appropriate. - // The panic would still happen during the call if we omit this, - // but we want Interface() and other operations to fail early. - methodReceiver(op, fv.rcvr, fv.method) - - return Value{ftyp.Common(), unsafe.Pointer(fv), v.flag&flagRO | flag(Func)} - */ - panic("todo: reflect.makeMethodValue") + // v.Type returns the actual type of the method value. + ftyp := *(*funcType)(unsafe.Pointer(v.Type().(*rtype))) + ptyp := rtypeOf(unsafe.Pointer(uintptr(0))) + ftyp.In = append([]*abi.Type{ptyp}, ftyp.In...) + typ := runtime.Struct("", 2*unsafe.Sizeof(0), abi.StructField{ + Name_: "llgo_ctx", + Typ: &ftyp.Type, + }, abi.StructField{ + Name_: "f", + Typ: ptyp, + Offset: unsafe.Sizeof(0), + }) + typ.TFlag |= abi.TFlagClosure + _, _, fn := methodReceiver(op, rcvr, int(v.flag)>>flagMethodShift) + fv := &struct { + fn unsafe.Pointer + env unsafe.Pointer + }{fn, v.ptr} + // Cause panic if method is not appropriate. + // The panic would still happen during the call if we omit this, + // but we want Interface() and other operations to fail early. + return Value{typ, unsafe.Pointer(fv), v.flag&flagRO | flagIndir | flag(Func)} } /*