Merge pull request #886 from visualfc/reflect.map
reflect: implement map
This commit is contained in:
@@ -11,6 +11,8 @@ func main() {
|
||||
callClosure()
|
||||
callMethod()
|
||||
callIMethod()
|
||||
mapDemo1()
|
||||
mapDemo2()
|
||||
}
|
||||
|
||||
func demo(n1, n2, n3, n4, n5, n6, n7, n8, n9 int, a ...interface{}) (int, int) {
|
||||
@@ -119,3 +121,63 @@ func callIMethod() {
|
||||
r2 := v2.Call([]reflect.Value{reflect.ValueOf(100)})
|
||||
println(r2[0].Int())
|
||||
}
|
||||
|
||||
func mapDemo1() {
|
||||
m := map[int]string{
|
||||
1: "hello",
|
||||
2: "world",
|
||||
}
|
||||
v := reflect.ValueOf(m)
|
||||
if v.Len() != 2 || len(v.MapKeys()) != 2 {
|
||||
panic("error")
|
||||
}
|
||||
if v.MapIndex(reflect.ValueOf(2)).String() != "world" {
|
||||
panic("MapIndex error")
|
||||
}
|
||||
v.SetMapIndex(reflect.ValueOf(2), reflect.ValueOf("todo"))
|
||||
if v.MapIndex(reflect.ValueOf(2)).String() != "todo" {
|
||||
panic("MapIndex error")
|
||||
}
|
||||
if v.MapIndex(reflect.ValueOf(0)).IsValid() {
|
||||
println("must invalid")
|
||||
}
|
||||
key := reflect.New(v.Type().Key()).Elem()
|
||||
value := reflect.New(v.Type().Elem()).Elem()
|
||||
iter := v.MapRange()
|
||||
for iter.Next() {
|
||||
key.SetIterKey(iter)
|
||||
value.SetIterValue(iter)
|
||||
if key.Int() != iter.Key().Int() || value.String() != iter.Value().String() {
|
||||
panic("MapIter error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func mapDemo2() {
|
||||
v := reflect.MakeMap(reflect.MapOf(reflect.TypeOf(0), reflect.TypeOf("")))
|
||||
v.SetMapIndex(reflect.ValueOf(1), reflect.ValueOf("hello"))
|
||||
v.SetMapIndex(reflect.ValueOf(2), reflect.ValueOf("world"))
|
||||
if v.Len() != 2 || len(v.MapKeys()) != 2 {
|
||||
panic("error")
|
||||
}
|
||||
if v.MapIndex(reflect.ValueOf(2)).String() != "world" {
|
||||
panic("MapIndex error")
|
||||
}
|
||||
v.SetMapIndex(reflect.ValueOf(2), reflect.ValueOf("todo"))
|
||||
if v.MapIndex(reflect.ValueOf(2)).String() != "todo" {
|
||||
panic("MapIndex error")
|
||||
}
|
||||
if v.MapIndex(reflect.ValueOf(0)).IsValid() {
|
||||
println("must invalid")
|
||||
}
|
||||
key := reflect.New(v.Type().Key()).Elem()
|
||||
value := reflect.New(v.Type().Elem()).Elem()
|
||||
iter := v.MapRange()
|
||||
for iter.Next() {
|
||||
key.SetIterKey(iter)
|
||||
value.SetIterValue(iter)
|
||||
if key.Int() != iter.Key().Int() || value.String() != iter.Value().String() {
|
||||
panic("MapIter error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,17 @@ source_filename = "main"
|
||||
@16 = private unnamed_addr constant [21 x i8] c"type assertion failed", align 1
|
||||
@__llgo_argc = global i32 0, align 4
|
||||
@__llgo_argv = global ptr null, align 8
|
||||
@"map[_llgo_int]_llgo_string" = linkonce global ptr null, align 8
|
||||
@17 = private unnamed_addr constant [7 x i8] c"topbits", align 1
|
||||
@18 = private unnamed_addr constant [4 x i8] c"keys", align 1
|
||||
@19 = private unnamed_addr constant [5 x i8] c"elems", align 1
|
||||
@20 = private unnamed_addr constant [8 x i8] c"overflow", align 1
|
||||
@21 = private unnamed_addr constant [5 x i8] c"hello", align 1
|
||||
@22 = private unnamed_addr constant [5 x i8] c"world", align 1
|
||||
@23 = private unnamed_addr constant [14 x i8] c"MapIndex error", align 1
|
||||
@24 = private unnamed_addr constant [4 x i8] c"todo", align 1
|
||||
@25 = private unnamed_addr constant [12 x i8] c"must invalid", align 1
|
||||
@26 = private unnamed_addr constant [13 x i8] c"MapIter error", align 1
|
||||
|
||||
define i64 @"main.(*T).Add"(ptr %0, i64 %1) {
|
||||
_llgo_0:
|
||||
@@ -639,9 +650,357 @@ _llgo_0:
|
||||
call void @main.callClosure()
|
||||
call void @main.callMethod()
|
||||
call void @main.callIMethod()
|
||||
call void @main.mapDemo1()
|
||||
call void @main.mapDemo2()
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
define void @main.mapDemo1() {
|
||||
_llgo_0:
|
||||
%0 = load ptr, ptr @"map[_llgo_int]_llgo_string", align 8
|
||||
%1 = call ptr @"github.com/goplus/llgo/internal/runtime.MakeMap"(ptr %0, i64 2)
|
||||
%2 = load ptr, ptr @"map[_llgo_int]_llgo_string", align 8
|
||||
%3 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 8)
|
||||
store i64 1, ptr %3, align 4
|
||||
%4 = call ptr @"github.com/goplus/llgo/internal/runtime.MapAssign"(ptr %2, ptr %1, ptr %3)
|
||||
store %"github.com/goplus/llgo/internal/runtime.String" { ptr @21, i64 5 }, ptr %4, align 8
|
||||
%5 = load ptr, ptr @"map[_llgo_int]_llgo_string", align 8
|
||||
%6 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 8)
|
||||
store i64 2, ptr %6, align 4
|
||||
%7 = call ptr @"github.com/goplus/llgo/internal/runtime.MapAssign"(ptr %5, ptr %1, ptr %6)
|
||||
store %"github.com/goplus/llgo/internal/runtime.String" { ptr @22, i64 5 }, ptr %7, align 8
|
||||
%8 = load ptr, ptr @"map[_llgo_int]_llgo_string", align 8
|
||||
%9 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %8, 0
|
||||
%10 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %9, ptr %1, 1
|
||||
%11 = call %reflect.Value @reflect.ValueOf(%"github.com/goplus/llgo/internal/runtime.eface" %10)
|
||||
%12 = call i64 @reflect.Value.Len(%reflect.Value %11)
|
||||
%13 = icmp ne i64 %12, 2
|
||||
br i1 %13, label %_llgo_1, label %_llgo_3
|
||||
|
||||
_llgo_1: ; preds = %_llgo_3, %_llgo_0
|
||||
%14 = load ptr, ptr @_llgo_string, align 8
|
||||
%15 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 16)
|
||||
store %"github.com/goplus/llgo/internal/runtime.String" { ptr @5, i64 5 }, ptr %15, align 8
|
||||
%16 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %14, 0
|
||||
%17 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %16, ptr %15, 1
|
||||
call void @"github.com/goplus/llgo/internal/runtime.Panic"(%"github.com/goplus/llgo/internal/runtime.eface" %17)
|
||||
unreachable
|
||||
|
||||
_llgo_2: ; preds = %_llgo_3
|
||||
%18 = load ptr, ptr @_llgo_int, align 8
|
||||
%19 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %18, 0
|
||||
%20 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %19, ptr inttoptr (i64 2 to ptr), 1
|
||||
%21 = call %reflect.Value @reflect.ValueOf(%"github.com/goplus/llgo/internal/runtime.eface" %20)
|
||||
%22 = call %reflect.Value @reflect.Value.MapIndex(%reflect.Value %11, %reflect.Value %21)
|
||||
%23 = call %"github.com/goplus/llgo/internal/runtime.String" @reflect.Value.String(%reflect.Value %22)
|
||||
%24 = call i1 @"github.com/goplus/llgo/internal/runtime.StringEqual"(%"github.com/goplus/llgo/internal/runtime.String" %23, %"github.com/goplus/llgo/internal/runtime.String" { ptr @22, i64 5 })
|
||||
%25 = xor i1 %24, true
|
||||
br i1 %25, label %_llgo_4, label %_llgo_5
|
||||
|
||||
_llgo_3: ; preds = %_llgo_0
|
||||
%26 = call %"github.com/goplus/llgo/internal/runtime.Slice" @reflect.Value.MapKeys(%reflect.Value %11)
|
||||
%27 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %26, 1
|
||||
%28 = icmp ne i64 %27, 2
|
||||
br i1 %28, label %_llgo_1, label %_llgo_2
|
||||
|
||||
_llgo_4: ; preds = %_llgo_2
|
||||
%29 = load ptr, ptr @_llgo_string, align 8
|
||||
%30 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 16)
|
||||
store %"github.com/goplus/llgo/internal/runtime.String" { ptr @23, i64 14 }, ptr %30, align 8
|
||||
%31 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %29, 0
|
||||
%32 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %31, ptr %30, 1
|
||||
call void @"github.com/goplus/llgo/internal/runtime.Panic"(%"github.com/goplus/llgo/internal/runtime.eface" %32)
|
||||
unreachable
|
||||
|
||||
_llgo_5: ; preds = %_llgo_2
|
||||
%33 = load ptr, ptr @_llgo_int, align 8
|
||||
%34 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %33, 0
|
||||
%35 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %34, ptr inttoptr (i64 2 to ptr), 1
|
||||
%36 = call %reflect.Value @reflect.ValueOf(%"github.com/goplus/llgo/internal/runtime.eface" %35)
|
||||
%37 = load ptr, ptr @_llgo_string, align 8
|
||||
%38 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 16)
|
||||
store %"github.com/goplus/llgo/internal/runtime.String" { ptr @24, i64 4 }, ptr %38, align 8
|
||||
%39 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %37, 0
|
||||
%40 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %39, ptr %38, 1
|
||||
%41 = call %reflect.Value @reflect.ValueOf(%"github.com/goplus/llgo/internal/runtime.eface" %40)
|
||||
call void @reflect.Value.SetMapIndex(%reflect.Value %11, %reflect.Value %36, %reflect.Value %41)
|
||||
%42 = load ptr, ptr @_llgo_int, align 8
|
||||
%43 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %42, 0
|
||||
%44 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %43, ptr inttoptr (i64 2 to ptr), 1
|
||||
%45 = call %reflect.Value @reflect.ValueOf(%"github.com/goplus/llgo/internal/runtime.eface" %44)
|
||||
%46 = call %reflect.Value @reflect.Value.MapIndex(%reflect.Value %11, %reflect.Value %45)
|
||||
%47 = call %"github.com/goplus/llgo/internal/runtime.String" @reflect.Value.String(%reflect.Value %46)
|
||||
%48 = call i1 @"github.com/goplus/llgo/internal/runtime.StringEqual"(%"github.com/goplus/llgo/internal/runtime.String" %47, %"github.com/goplus/llgo/internal/runtime.String" { ptr @24, i64 4 })
|
||||
%49 = xor i1 %48, true
|
||||
br i1 %49, label %_llgo_6, label %_llgo_7
|
||||
|
||||
_llgo_6: ; preds = %_llgo_5
|
||||
%50 = load ptr, ptr @_llgo_string, align 8
|
||||
%51 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 16)
|
||||
store %"github.com/goplus/llgo/internal/runtime.String" { ptr @23, i64 14 }, ptr %51, align 8
|
||||
%52 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %50, 0
|
||||
%53 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %52, ptr %51, 1
|
||||
call void @"github.com/goplus/llgo/internal/runtime.Panic"(%"github.com/goplus/llgo/internal/runtime.eface" %53)
|
||||
unreachable
|
||||
|
||||
_llgo_7: ; preds = %_llgo_5
|
||||
%54 = load ptr, ptr @_llgo_int, align 8
|
||||
%55 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %54, 0
|
||||
%56 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %55, ptr null, 1
|
||||
%57 = call %reflect.Value @reflect.ValueOf(%"github.com/goplus/llgo/internal/runtime.eface" %56)
|
||||
%58 = call %reflect.Value @reflect.Value.MapIndex(%reflect.Value %11, %reflect.Value %57)
|
||||
%59 = call i1 @reflect.Value.IsValid(%reflect.Value %58)
|
||||
br i1 %59, label %_llgo_8, label %_llgo_9
|
||||
|
||||
_llgo_8: ; preds = %_llgo_7
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" { ptr @25, i64 12 })
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||
br label %_llgo_9
|
||||
|
||||
_llgo_9: ; preds = %_llgo_8, %_llgo_7
|
||||
%60 = call %"github.com/goplus/llgo/internal/runtime.iface" @reflect.Value.Type(%reflect.Value %11)
|
||||
%61 = call ptr @"github.com/goplus/llgo/internal/runtime.IfacePtrData"(%"github.com/goplus/llgo/internal/runtime.iface" %60)
|
||||
%62 = extractvalue %"github.com/goplus/llgo/internal/runtime.iface" %60, 0
|
||||
%63 = getelementptr ptr, ptr %62, i64 18
|
||||
%64 = load ptr, ptr %63, align 8
|
||||
%65 = insertvalue { ptr, ptr } undef, ptr %64, 0
|
||||
%66 = insertvalue { ptr, ptr } %65, ptr %61, 1
|
||||
%67 = extractvalue { ptr, ptr } %66, 1
|
||||
%68 = extractvalue { ptr, ptr } %66, 0
|
||||
%69 = call %"github.com/goplus/llgo/internal/runtime.iface" %68(ptr %67)
|
||||
%70 = call %reflect.Value @reflect.New(%"github.com/goplus/llgo/internal/runtime.iface" %69)
|
||||
%71 = call %reflect.Value @reflect.Value.Elem(%reflect.Value %70)
|
||||
%72 = call %"github.com/goplus/llgo/internal/runtime.iface" @reflect.Value.Type(%reflect.Value %11)
|
||||
%73 = call ptr @"github.com/goplus/llgo/internal/runtime.IfacePtrData"(%"github.com/goplus/llgo/internal/runtime.iface" %72)
|
||||
%74 = extractvalue %"github.com/goplus/llgo/internal/runtime.iface" %72, 0
|
||||
%75 = getelementptr ptr, ptr %74, i64 9
|
||||
%76 = load ptr, ptr %75, align 8
|
||||
%77 = insertvalue { ptr, ptr } undef, ptr %76, 0
|
||||
%78 = insertvalue { ptr, ptr } %77, ptr %73, 1
|
||||
%79 = extractvalue { ptr, ptr } %78, 1
|
||||
%80 = extractvalue { ptr, ptr } %78, 0
|
||||
%81 = call %"github.com/goplus/llgo/internal/runtime.iface" %80(ptr %79)
|
||||
%82 = call %reflect.Value @reflect.New(%"github.com/goplus/llgo/internal/runtime.iface" %81)
|
||||
%83 = call %reflect.Value @reflect.Value.Elem(%reflect.Value %82)
|
||||
%84 = call ptr @reflect.Value.MapRange(%reflect.Value %11)
|
||||
br label %_llgo_12
|
||||
|
||||
_llgo_10: ; preds = %_llgo_12
|
||||
call void @reflect.Value.SetIterKey(%reflect.Value %71, ptr %84)
|
||||
call void @reflect.Value.SetIterValue(%reflect.Value %83, ptr %84)
|
||||
%85 = call i64 @reflect.Value.Int(%reflect.Value %71)
|
||||
%86 = call %reflect.Value @"reflect.(*MapIter).Key"(ptr %84)
|
||||
%87 = call i64 @reflect.Value.Int(%reflect.Value %86)
|
||||
%88 = icmp ne i64 %85, %87
|
||||
br i1 %88, label %_llgo_13, label %_llgo_14
|
||||
|
||||
_llgo_11: ; preds = %_llgo_12
|
||||
ret void
|
||||
|
||||
_llgo_12: ; preds = %_llgo_14, %_llgo_9
|
||||
%89 = call i1 @"reflect.(*MapIter).Next"(ptr %84)
|
||||
br i1 %89, label %_llgo_10, label %_llgo_11
|
||||
|
||||
_llgo_13: ; preds = %_llgo_14, %_llgo_10
|
||||
%90 = load ptr, ptr @_llgo_string, align 8
|
||||
%91 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 16)
|
||||
store %"github.com/goplus/llgo/internal/runtime.String" { ptr @26, i64 13 }, ptr %91, align 8
|
||||
%92 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %90, 0
|
||||
%93 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %92, ptr %91, 1
|
||||
call void @"github.com/goplus/llgo/internal/runtime.Panic"(%"github.com/goplus/llgo/internal/runtime.eface" %93)
|
||||
unreachable
|
||||
|
||||
_llgo_14: ; preds = %_llgo_10
|
||||
%94 = call %"github.com/goplus/llgo/internal/runtime.String" @reflect.Value.String(%reflect.Value %83)
|
||||
%95 = call %reflect.Value @"reflect.(*MapIter).Value"(ptr %84)
|
||||
%96 = call %"github.com/goplus/llgo/internal/runtime.String" @reflect.Value.String(%reflect.Value %95)
|
||||
%97 = call i1 @"github.com/goplus/llgo/internal/runtime.StringEqual"(%"github.com/goplus/llgo/internal/runtime.String" %94, %"github.com/goplus/llgo/internal/runtime.String" %96)
|
||||
%98 = xor i1 %97, true
|
||||
br i1 %98, label %_llgo_13, label %_llgo_12
|
||||
}
|
||||
|
||||
define void @main.mapDemo2() {
|
||||
_llgo_0:
|
||||
%0 = load ptr, ptr @_llgo_int, align 8
|
||||
%1 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %0, 0
|
||||
%2 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %1, ptr null, 1
|
||||
%3 = call %"github.com/goplus/llgo/internal/runtime.iface" @reflect.TypeOf(%"github.com/goplus/llgo/internal/runtime.eface" %2)
|
||||
%4 = load ptr, ptr @_llgo_string, align 8
|
||||
%5 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 16)
|
||||
store %"github.com/goplus/llgo/internal/runtime.String" zeroinitializer, ptr %5, align 8
|
||||
%6 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %4, 0
|
||||
%7 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %6, ptr %5, 1
|
||||
%8 = call %"github.com/goplus/llgo/internal/runtime.iface" @reflect.TypeOf(%"github.com/goplus/llgo/internal/runtime.eface" %7)
|
||||
%9 = call %"github.com/goplus/llgo/internal/runtime.iface" @reflect.MapOf(%"github.com/goplus/llgo/internal/runtime.iface" %3, %"github.com/goplus/llgo/internal/runtime.iface" %8)
|
||||
%10 = call %reflect.Value @reflect.MakeMap(%"github.com/goplus/llgo/internal/runtime.iface" %9)
|
||||
%11 = load ptr, ptr @_llgo_int, align 8
|
||||
%12 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %11, 0
|
||||
%13 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %12, ptr inttoptr (i64 1 to ptr), 1
|
||||
%14 = call %reflect.Value @reflect.ValueOf(%"github.com/goplus/llgo/internal/runtime.eface" %13)
|
||||
%15 = load ptr, ptr @_llgo_string, align 8
|
||||
%16 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 16)
|
||||
store %"github.com/goplus/llgo/internal/runtime.String" { ptr @21, i64 5 }, ptr %16, align 8
|
||||
%17 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %15, 0
|
||||
%18 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %17, ptr %16, 1
|
||||
%19 = call %reflect.Value @reflect.ValueOf(%"github.com/goplus/llgo/internal/runtime.eface" %18)
|
||||
call void @reflect.Value.SetMapIndex(%reflect.Value %10, %reflect.Value %14, %reflect.Value %19)
|
||||
%20 = load ptr, ptr @_llgo_int, align 8
|
||||
%21 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %20, 0
|
||||
%22 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %21, ptr inttoptr (i64 2 to ptr), 1
|
||||
%23 = call %reflect.Value @reflect.ValueOf(%"github.com/goplus/llgo/internal/runtime.eface" %22)
|
||||
%24 = load ptr, ptr @_llgo_string, align 8
|
||||
%25 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 16)
|
||||
store %"github.com/goplus/llgo/internal/runtime.String" { ptr @22, i64 5 }, ptr %25, align 8
|
||||
%26 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %24, 0
|
||||
%27 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %26, ptr %25, 1
|
||||
%28 = call %reflect.Value @reflect.ValueOf(%"github.com/goplus/llgo/internal/runtime.eface" %27)
|
||||
call void @reflect.Value.SetMapIndex(%reflect.Value %10, %reflect.Value %23, %reflect.Value %28)
|
||||
%29 = call i64 @reflect.Value.Len(%reflect.Value %10)
|
||||
%30 = icmp ne i64 %29, 2
|
||||
br i1 %30, label %_llgo_1, label %_llgo_3
|
||||
|
||||
_llgo_1: ; preds = %_llgo_3, %_llgo_0
|
||||
%31 = load ptr, ptr @_llgo_string, align 8
|
||||
%32 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 16)
|
||||
store %"github.com/goplus/llgo/internal/runtime.String" { ptr @5, i64 5 }, ptr %32, align 8
|
||||
%33 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %31, 0
|
||||
%34 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %33, ptr %32, 1
|
||||
call void @"github.com/goplus/llgo/internal/runtime.Panic"(%"github.com/goplus/llgo/internal/runtime.eface" %34)
|
||||
unreachable
|
||||
|
||||
_llgo_2: ; preds = %_llgo_3
|
||||
%35 = load ptr, ptr @_llgo_int, align 8
|
||||
%36 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %35, 0
|
||||
%37 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %36, ptr inttoptr (i64 2 to ptr), 1
|
||||
%38 = call %reflect.Value @reflect.ValueOf(%"github.com/goplus/llgo/internal/runtime.eface" %37)
|
||||
%39 = call %reflect.Value @reflect.Value.MapIndex(%reflect.Value %10, %reflect.Value %38)
|
||||
%40 = call %"github.com/goplus/llgo/internal/runtime.String" @reflect.Value.String(%reflect.Value %39)
|
||||
%41 = call i1 @"github.com/goplus/llgo/internal/runtime.StringEqual"(%"github.com/goplus/llgo/internal/runtime.String" %40, %"github.com/goplus/llgo/internal/runtime.String" { ptr @22, i64 5 })
|
||||
%42 = xor i1 %41, true
|
||||
br i1 %42, label %_llgo_4, label %_llgo_5
|
||||
|
||||
_llgo_3: ; preds = %_llgo_0
|
||||
%43 = call %"github.com/goplus/llgo/internal/runtime.Slice" @reflect.Value.MapKeys(%reflect.Value %10)
|
||||
%44 = extractvalue %"github.com/goplus/llgo/internal/runtime.Slice" %43, 1
|
||||
%45 = icmp ne i64 %44, 2
|
||||
br i1 %45, label %_llgo_1, label %_llgo_2
|
||||
|
||||
_llgo_4: ; preds = %_llgo_2
|
||||
%46 = load ptr, ptr @_llgo_string, align 8
|
||||
%47 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 16)
|
||||
store %"github.com/goplus/llgo/internal/runtime.String" { ptr @23, i64 14 }, ptr %47, align 8
|
||||
%48 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %46, 0
|
||||
%49 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %48, ptr %47, 1
|
||||
call void @"github.com/goplus/llgo/internal/runtime.Panic"(%"github.com/goplus/llgo/internal/runtime.eface" %49)
|
||||
unreachable
|
||||
|
||||
_llgo_5: ; preds = %_llgo_2
|
||||
%50 = load ptr, ptr @_llgo_int, align 8
|
||||
%51 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %50, 0
|
||||
%52 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %51, ptr inttoptr (i64 2 to ptr), 1
|
||||
%53 = call %reflect.Value @reflect.ValueOf(%"github.com/goplus/llgo/internal/runtime.eface" %52)
|
||||
%54 = load ptr, ptr @_llgo_string, align 8
|
||||
%55 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 16)
|
||||
store %"github.com/goplus/llgo/internal/runtime.String" { ptr @24, i64 4 }, ptr %55, align 8
|
||||
%56 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %54, 0
|
||||
%57 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %56, ptr %55, 1
|
||||
%58 = call %reflect.Value @reflect.ValueOf(%"github.com/goplus/llgo/internal/runtime.eface" %57)
|
||||
call void @reflect.Value.SetMapIndex(%reflect.Value %10, %reflect.Value %53, %reflect.Value %58)
|
||||
%59 = load ptr, ptr @_llgo_int, align 8
|
||||
%60 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %59, 0
|
||||
%61 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %60, ptr inttoptr (i64 2 to ptr), 1
|
||||
%62 = call %reflect.Value @reflect.ValueOf(%"github.com/goplus/llgo/internal/runtime.eface" %61)
|
||||
%63 = call %reflect.Value @reflect.Value.MapIndex(%reflect.Value %10, %reflect.Value %62)
|
||||
%64 = call %"github.com/goplus/llgo/internal/runtime.String" @reflect.Value.String(%reflect.Value %63)
|
||||
%65 = call i1 @"github.com/goplus/llgo/internal/runtime.StringEqual"(%"github.com/goplus/llgo/internal/runtime.String" %64, %"github.com/goplus/llgo/internal/runtime.String" { ptr @24, i64 4 })
|
||||
%66 = xor i1 %65, true
|
||||
br i1 %66, label %_llgo_6, label %_llgo_7
|
||||
|
||||
_llgo_6: ; preds = %_llgo_5
|
||||
%67 = load ptr, ptr @_llgo_string, align 8
|
||||
%68 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 16)
|
||||
store %"github.com/goplus/llgo/internal/runtime.String" { ptr @23, i64 14 }, ptr %68, align 8
|
||||
%69 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %67, 0
|
||||
%70 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %69, ptr %68, 1
|
||||
call void @"github.com/goplus/llgo/internal/runtime.Panic"(%"github.com/goplus/llgo/internal/runtime.eface" %70)
|
||||
unreachable
|
||||
|
||||
_llgo_7: ; preds = %_llgo_5
|
||||
%71 = load ptr, ptr @_llgo_int, align 8
|
||||
%72 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %71, 0
|
||||
%73 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %72, ptr null, 1
|
||||
%74 = call %reflect.Value @reflect.ValueOf(%"github.com/goplus/llgo/internal/runtime.eface" %73)
|
||||
%75 = call %reflect.Value @reflect.Value.MapIndex(%reflect.Value %10, %reflect.Value %74)
|
||||
%76 = call i1 @reflect.Value.IsValid(%reflect.Value %75)
|
||||
br i1 %76, label %_llgo_8, label %_llgo_9
|
||||
|
||||
_llgo_8: ; preds = %_llgo_7
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String" { ptr @25, i64 12 })
|
||||
call void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8 10)
|
||||
br label %_llgo_9
|
||||
|
||||
_llgo_9: ; preds = %_llgo_8, %_llgo_7
|
||||
%77 = call %"github.com/goplus/llgo/internal/runtime.iface" @reflect.Value.Type(%reflect.Value %10)
|
||||
%78 = call ptr @"github.com/goplus/llgo/internal/runtime.IfacePtrData"(%"github.com/goplus/llgo/internal/runtime.iface" %77)
|
||||
%79 = extractvalue %"github.com/goplus/llgo/internal/runtime.iface" %77, 0
|
||||
%80 = getelementptr ptr, ptr %79, i64 18
|
||||
%81 = load ptr, ptr %80, align 8
|
||||
%82 = insertvalue { ptr, ptr } undef, ptr %81, 0
|
||||
%83 = insertvalue { ptr, ptr } %82, ptr %78, 1
|
||||
%84 = extractvalue { ptr, ptr } %83, 1
|
||||
%85 = extractvalue { ptr, ptr } %83, 0
|
||||
%86 = call %"github.com/goplus/llgo/internal/runtime.iface" %85(ptr %84)
|
||||
%87 = call %reflect.Value @reflect.New(%"github.com/goplus/llgo/internal/runtime.iface" %86)
|
||||
%88 = call %reflect.Value @reflect.Value.Elem(%reflect.Value %87)
|
||||
%89 = call %"github.com/goplus/llgo/internal/runtime.iface" @reflect.Value.Type(%reflect.Value %10)
|
||||
%90 = call ptr @"github.com/goplus/llgo/internal/runtime.IfacePtrData"(%"github.com/goplus/llgo/internal/runtime.iface" %89)
|
||||
%91 = extractvalue %"github.com/goplus/llgo/internal/runtime.iface" %89, 0
|
||||
%92 = getelementptr ptr, ptr %91, i64 9
|
||||
%93 = load ptr, ptr %92, align 8
|
||||
%94 = insertvalue { ptr, ptr } undef, ptr %93, 0
|
||||
%95 = insertvalue { ptr, ptr } %94, ptr %90, 1
|
||||
%96 = extractvalue { ptr, ptr } %95, 1
|
||||
%97 = extractvalue { ptr, ptr } %95, 0
|
||||
%98 = call %"github.com/goplus/llgo/internal/runtime.iface" %97(ptr %96)
|
||||
%99 = call %reflect.Value @reflect.New(%"github.com/goplus/llgo/internal/runtime.iface" %98)
|
||||
%100 = call %reflect.Value @reflect.Value.Elem(%reflect.Value %99)
|
||||
%101 = call ptr @reflect.Value.MapRange(%reflect.Value %10)
|
||||
br label %_llgo_12
|
||||
|
||||
_llgo_10: ; preds = %_llgo_12
|
||||
call void @reflect.Value.SetIterKey(%reflect.Value %88, ptr %101)
|
||||
call void @reflect.Value.SetIterValue(%reflect.Value %100, ptr %101)
|
||||
%102 = call i64 @reflect.Value.Int(%reflect.Value %88)
|
||||
%103 = call %reflect.Value @"reflect.(*MapIter).Key"(ptr %101)
|
||||
%104 = call i64 @reflect.Value.Int(%reflect.Value %103)
|
||||
%105 = icmp ne i64 %102, %104
|
||||
br i1 %105, label %_llgo_13, label %_llgo_14
|
||||
|
||||
_llgo_11: ; preds = %_llgo_12
|
||||
ret void
|
||||
|
||||
_llgo_12: ; preds = %_llgo_14, %_llgo_9
|
||||
%106 = call i1 @"reflect.(*MapIter).Next"(ptr %101)
|
||||
br i1 %106, label %_llgo_10, label %_llgo_11
|
||||
|
||||
_llgo_13: ; preds = %_llgo_14, %_llgo_10
|
||||
%107 = load ptr, ptr @_llgo_string, align 8
|
||||
%108 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 16)
|
||||
store %"github.com/goplus/llgo/internal/runtime.String" { ptr @26, i64 13 }, ptr %108, align 8
|
||||
%109 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" undef, ptr %107, 0
|
||||
%110 = insertvalue %"github.com/goplus/llgo/internal/runtime.eface" %109, ptr %108, 1
|
||||
call void @"github.com/goplus/llgo/internal/runtime.Panic"(%"github.com/goplus/llgo/internal/runtime.eface" %110)
|
||||
unreachable
|
||||
|
||||
_llgo_14: ; preds = %_llgo_10
|
||||
%111 = call %"github.com/goplus/llgo/internal/runtime.String" @reflect.Value.String(%reflect.Value %100)
|
||||
%112 = call %reflect.Value @"reflect.(*MapIter).Value"(ptr %101)
|
||||
%113 = call %"github.com/goplus/llgo/internal/runtime.String" @reflect.Value.String(%reflect.Value %112)
|
||||
%114 = call i1 @"github.com/goplus/llgo/internal/runtime.StringEqual"(%"github.com/goplus/llgo/internal/runtime.String" %111, %"github.com/goplus/llgo/internal/runtime.String" %113)
|
||||
%115 = xor i1 %114, true
|
||||
br i1 %115, label %_llgo_13, label %_llgo_12
|
||||
}
|
||||
|
||||
declare void @"github.com/goplus/llgo/internal/runtime.PrintString"(%"github.com/goplus/llgo/internal/runtime.String")
|
||||
|
||||
declare void @"github.com/goplus/llgo/internal/runtime.PrintByte"(i8)
|
||||
@@ -948,6 +1307,43 @@ _llgo_22: ; preds = %_llgo_21, %_llgo_20
|
||||
%173 = insertvalue %"github.com/goplus/llgo/internal/runtime.Slice" %172, i64 2, 2
|
||||
%174 = call ptr @"github.com/goplus/llgo/internal/runtime.Struct"(%"github.com/goplus/llgo/internal/runtime.String" { ptr @3, i64 4 }, i64 16, %"github.com/goplus/llgo/internal/runtime.Slice" %173)
|
||||
store ptr %174, ptr @"main.struct$zCLFE3aa581X7nuJztqlq4JjJDbHkfoMY0CexWOzH8A", align 8
|
||||
%175 = load ptr, ptr @"map[_llgo_int]_llgo_string", align 8
|
||||
%176 = icmp eq ptr %175, null
|
||||
br i1 %176, label %_llgo_23, label %_llgo_24
|
||||
|
||||
_llgo_23: ; preds = %_llgo_22
|
||||
%177 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 34)
|
||||
%178 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 24)
|
||||
%179 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 40)
|
||||
%180 = call ptr @"github.com/goplus/llgo/internal/runtime.ArrayOf"(i64 8, ptr %179)
|
||||
%181 = call %"github.com/goplus/llgo/internal/abi.StructField" @"github.com/goplus/llgo/internal/runtime.StructField"(%"github.com/goplus/llgo/internal/runtime.String" { ptr @17, i64 7 }, ptr %180, i64 0, %"github.com/goplus/llgo/internal/runtime.String" zeroinitializer, i1 false)
|
||||
%182 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 34)
|
||||
%183 = call ptr @"github.com/goplus/llgo/internal/runtime.ArrayOf"(i64 8, ptr %182)
|
||||
%184 = call %"github.com/goplus/llgo/internal/abi.StructField" @"github.com/goplus/llgo/internal/runtime.StructField"(%"github.com/goplus/llgo/internal/runtime.String" { ptr @18, i64 4 }, ptr %183, i64 8, %"github.com/goplus/llgo/internal/runtime.String" zeroinitializer, i1 false)
|
||||
%185 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 24)
|
||||
%186 = call ptr @"github.com/goplus/llgo/internal/runtime.ArrayOf"(i64 8, ptr %185)
|
||||
%187 = call %"github.com/goplus/llgo/internal/abi.StructField" @"github.com/goplus/llgo/internal/runtime.StructField"(%"github.com/goplus/llgo/internal/runtime.String" { ptr @19, i64 5 }, ptr %186, i64 72, %"github.com/goplus/llgo/internal/runtime.String" zeroinitializer, i1 false)
|
||||
%188 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 58)
|
||||
%189 = call %"github.com/goplus/llgo/internal/abi.StructField" @"github.com/goplus/llgo/internal/runtime.StructField"(%"github.com/goplus/llgo/internal/runtime.String" { ptr @20, i64 8 }, ptr %188, i64 200, %"github.com/goplus/llgo/internal/runtime.String" zeroinitializer, i1 false)
|
||||
%190 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocU"(i64 224)
|
||||
%191 = getelementptr %"github.com/goplus/llgo/internal/abi.StructField", ptr %190, i64 0
|
||||
store %"github.com/goplus/llgo/internal/abi.StructField" %181, ptr %191, align 8
|
||||
%192 = getelementptr %"github.com/goplus/llgo/internal/abi.StructField", ptr %190, i64 1
|
||||
store %"github.com/goplus/llgo/internal/abi.StructField" %184, ptr %192, align 8
|
||||
%193 = getelementptr %"github.com/goplus/llgo/internal/abi.StructField", ptr %190, i64 2
|
||||
store %"github.com/goplus/llgo/internal/abi.StructField" %187, ptr %193, align 8
|
||||
%194 = getelementptr %"github.com/goplus/llgo/internal/abi.StructField", ptr %190, i64 3
|
||||
store %"github.com/goplus/llgo/internal/abi.StructField" %189, ptr %194, align 8
|
||||
%195 = insertvalue %"github.com/goplus/llgo/internal/runtime.Slice" undef, ptr %190, 0
|
||||
%196 = insertvalue %"github.com/goplus/llgo/internal/runtime.Slice" %195, i64 4, 1
|
||||
%197 = insertvalue %"github.com/goplus/llgo/internal/runtime.Slice" %196, i64 4, 2
|
||||
%198 = call ptr @"github.com/goplus/llgo/internal/runtime.Struct"(%"github.com/goplus/llgo/internal/runtime.String" { ptr @3, i64 4 }, i64 208, %"github.com/goplus/llgo/internal/runtime.Slice" %197)
|
||||
%199 = call ptr @"github.com/goplus/llgo/internal/runtime.MapOf"(ptr %177, ptr %178, ptr %198, i64 4)
|
||||
call void @"github.com/goplus/llgo/internal/runtime.SetDirectIface"(ptr %199)
|
||||
store ptr %199, ptr @"map[_llgo_int]_llgo_string", align 8
|
||||
br label %_llgo_24
|
||||
|
||||
_llgo_24: ; preds = %_llgo_23, %_llgo_22
|
||||
ret void
|
||||
}
|
||||
|
||||
@@ -1016,3 +1412,47 @@ declare %"github.com/goplus/llgo/internal/runtime.Slice" @reflect.Value.CallSlic
|
||||
declare void @reflect.init()
|
||||
|
||||
declare void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||
|
||||
declare ptr @"github.com/goplus/llgo/internal/runtime.MapOf"(ptr, ptr, ptr, i64)
|
||||
|
||||
declare ptr @"github.com/goplus/llgo/internal/runtime.ArrayOf"(i64, ptr)
|
||||
|
||||
declare ptr @"github.com/goplus/llgo/internal/runtime.MakeMap"(ptr, i64)
|
||||
|
||||
declare ptr @"github.com/goplus/llgo/internal/runtime.MapAssign"(ptr, ptr, ptr)
|
||||
|
||||
declare i64 @reflect.Value.Len(%reflect.Value)
|
||||
|
||||
declare %"github.com/goplus/llgo/internal/runtime.Slice" @reflect.Value.MapKeys(%reflect.Value)
|
||||
|
||||
declare %reflect.Value @reflect.Value.MapIndex(%reflect.Value, %reflect.Value)
|
||||
|
||||
declare %"github.com/goplus/llgo/internal/runtime.String" @reflect.Value.String(%reflect.Value)
|
||||
|
||||
declare i1 @"github.com/goplus/llgo/internal/runtime.StringEqual"(%"github.com/goplus/llgo/internal/runtime.String", %"github.com/goplus/llgo/internal/runtime.String")
|
||||
|
||||
declare void @reflect.Value.SetMapIndex(%reflect.Value, %reflect.Value, %reflect.Value)
|
||||
|
||||
declare i1 @reflect.Value.IsValid(%reflect.Value)
|
||||
|
||||
declare %reflect.Value @reflect.New(%"github.com/goplus/llgo/internal/runtime.iface")
|
||||
|
||||
declare %reflect.Value @reflect.Value.Elem(%reflect.Value)
|
||||
|
||||
declare ptr @reflect.Value.MapRange(%reflect.Value)
|
||||
|
||||
declare i1 @"reflect.(*MapIter).Next"(ptr)
|
||||
|
||||
declare void @reflect.Value.SetIterKey(%reflect.Value, ptr)
|
||||
|
||||
declare void @reflect.Value.SetIterValue(%reflect.Value, ptr)
|
||||
|
||||
declare %reflect.Value @"reflect.(*MapIter).Key"(ptr)
|
||||
|
||||
declare %reflect.Value @"reflect.(*MapIter).Value"(ptr)
|
||||
|
||||
declare %"github.com/goplus/llgo/internal/runtime.iface" @reflect.TypeOf(%"github.com/goplus/llgo/internal/runtime.eface")
|
||||
|
||||
declare %"github.com/goplus/llgo/internal/runtime.iface" @reflect.MapOf(%"github.com/goplus/llgo/internal/runtime.iface", %"github.com/goplus/llgo/internal/runtime.iface")
|
||||
|
||||
declare %reflect.Value @reflect.MakeMap(%"github.com/goplus/llgo/internal/runtime.iface")
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"github.com/goplus/llgo/internal/abi"
|
||||
"github.com/goplus/llgo/internal/lib/sync"
|
||||
"github.com/goplus/llgo/internal/runtime"
|
||||
"github.com/goplus/llgo/internal/runtime/goarch"
|
||||
)
|
||||
|
||||
// Type is the representation of a Go type.
|
||||
@@ -1023,19 +1024,8 @@ func rtypeOf(i any) *abi.Type {
|
||||
return eface.typ
|
||||
}
|
||||
|
||||
/* TODO(xsw):
|
||||
// ptrMap is the cache for PointerTo.
|
||||
var ptrMap sync.Map // map[*rtype]*ptrType
|
||||
*/
|
||||
|
||||
var ptrMap struct {
|
||||
sync.Mutex
|
||||
m map[*rtype]*ptrType
|
||||
}
|
||||
|
||||
func init() {
|
||||
ptrMap.m = make(map[*rtype]*ptrType)
|
||||
}
|
||||
|
||||
// PtrTo returns the pointer type with element t.
|
||||
// For example, if t represents type Foo, PtrTo(t) represents *Foo.
|
||||
@@ -1056,8 +1046,8 @@ func (t *rtype) ptrTo() *abi.Type {
|
||||
return at.PtrToThis_
|
||||
}
|
||||
// Check the cache.
|
||||
if pi, ok := ptrMap.m[t]; ok {
|
||||
return &pi.Type
|
||||
if pi, ok := ptrMap.Load(t); ok {
|
||||
return &pi.(*ptrType).Type
|
||||
}
|
||||
|
||||
// Look in known types.
|
||||
@@ -1092,10 +1082,8 @@ func (t *rtype) ptrTo() *abi.Type {
|
||||
|
||||
pp.Elem = at
|
||||
|
||||
ptrMap.m[t] = &pp
|
||||
return &pp.Type
|
||||
//pi, _ := ptrMap.LoadOrStore(t, &pp)
|
||||
//return &pi.(*ptrType).Type
|
||||
pi, _ := ptrMap.LoadOrStore(t, &pp)
|
||||
return &pi.(*ptrType).Type
|
||||
}
|
||||
|
||||
func ptrTo(t *abi.Type) *abi.Type {
|
||||
@@ -1299,13 +1287,13 @@ func haveIdenticalUnderlyingType(T, V *abi.Type, cmpTags bool) bool {
|
||||
func SliceOf(t Type) Type {
|
||||
typ := t.common()
|
||||
|
||||
/* TODO(xsw): no cache
|
||||
// Look in cache.
|
||||
ckey := cacheKey{Slice, typ, nil, 0}
|
||||
if slice, ok := lookupCache.Load(ckey); ok {
|
||||
return slice.(Type)
|
||||
}
|
||||
|
||||
/*
|
||||
// Look in known types.
|
||||
s := "[]" + stringFor(typ)
|
||||
for _, tt := range typesByString(s) {
|
||||
@@ -1318,12 +1306,8 @@ func SliceOf(t Type) Type {
|
||||
*/
|
||||
|
||||
slice := runtime.SliceOf(typ)
|
||||
|
||||
// TODO(xsw):
|
||||
// ti, _ := lookupCache.LoadOrStore(ckey, toRType(&slice.Type))
|
||||
// return ti.(Type)
|
||||
|
||||
return toType(slice)
|
||||
ti, _ := lookupCache.LoadOrStore(ckey, toRType(slice))
|
||||
return ti.(Type)
|
||||
}
|
||||
|
||||
// toType converts from a *rtype to a Type that can be returned
|
||||
@@ -1338,6 +1322,19 @@ func toType(t *abi.Type) Type {
|
||||
return toRType(t)
|
||||
}
|
||||
|
||||
// The lookupCache caches ArrayOf, ChanOf, MapOf and SliceOf lookups.
|
||||
var lookupCache sync.Map // map[cacheKey]*rtype
|
||||
|
||||
// A cacheKey is the key for use in the lookupCache.
|
||||
// Four values describe any of the types we are looking for:
|
||||
// type kind, one or two subtypes, and an extra integer.
|
||||
type cacheKey struct {
|
||||
kind Kind
|
||||
t1 *abi.Type
|
||||
t2 *abi.Type
|
||||
extra uintptr
|
||||
}
|
||||
|
||||
// The funcLookupCache caches FuncOf lookups.
|
||||
// FuncOf does not share the common lookupCache since cacheKey is not
|
||||
// sufficient to represent functions unambiguously.
|
||||
@@ -1346,11 +1343,7 @@ var funcLookupCache struct {
|
||||
|
||||
// m is a map[uint32][]*rtype keyed by the hash calculated in FuncOf.
|
||||
// Elements of m are append-only and thus safe for concurrent reading.
|
||||
m map[uint32][]*abi.Type
|
||||
}
|
||||
|
||||
func init() {
|
||||
funcLookupCache.m = make(map[uint32][]*abi.Type)
|
||||
m sync.Map
|
||||
}
|
||||
|
||||
// FuncOf returns the function type with the given argument and result types.
|
||||
@@ -1401,8 +1394,8 @@ func FuncOf(in, out []Type, variadic bool) Type {
|
||||
defer funcLookupCache.Unlock()
|
||||
|
||||
// Look in cache.
|
||||
if ts, ok := funcLookupCache.m[hash]; ok {
|
||||
for _, t := range ts {
|
||||
if ts, ok := funcLookupCache.m.Load(hash); ok {
|
||||
for _, t := range ts.([]*abi.Type) {
|
||||
if haveIdenticalUnderlyingType(&ft.Type, t, true) {
|
||||
return toRType(t)
|
||||
}
|
||||
@@ -1410,8 +1403,11 @@ func FuncOf(in, out []Type, variadic bool) Type {
|
||||
}
|
||||
|
||||
addToCache := func(tt *abi.Type) Type {
|
||||
rts := funcLookupCache.m[hash]
|
||||
funcLookupCache.m[hash] = append(rts, tt)
|
||||
var rts []*abi.Type
|
||||
if rti, ok := funcLookupCache.m.Load(hash); ok {
|
||||
rts = rti.([]*abi.Type)
|
||||
}
|
||||
funcLookupCache.m.Store(hash, append(rts, tt))
|
||||
return toType(tt)
|
||||
}
|
||||
str := funcStr(ft)
|
||||
@@ -1466,3 +1462,244 @@ func funcStr(ft *funcType) string {
|
||||
}
|
||||
return string(repr)
|
||||
}
|
||||
|
||||
// MapOf returns the map type with the given key and element types.
|
||||
// For example, if k represents int and e represents string,
|
||||
// MapOf(k, e) represents map[int]string.
|
||||
//
|
||||
// If the key type is not a valid map key type (that is, if it does
|
||||
// not implement Go's == operator), MapOf panics.
|
||||
func MapOf(key, elem Type) Type {
|
||||
ktyp := key.common()
|
||||
etyp := elem.common()
|
||||
|
||||
if ktyp.Equal == nil {
|
||||
panic("reflect.MapOf: invalid key type " + stringFor(ktyp))
|
||||
}
|
||||
|
||||
// Look in cache.
|
||||
ckey := cacheKey{Map, ktyp, etyp, 0}
|
||||
if mt, ok := lookupCache.Load(ckey); ok {
|
||||
return mt.(Type)
|
||||
}
|
||||
|
||||
// Look in known types.
|
||||
s := "map[" + stringFor(ktyp) + "]" + stringFor(etyp)
|
||||
// for _, tt := range typesByString(s) {
|
||||
// mt := (*mapType)(unsafe.Pointer(tt))
|
||||
// if mt.Key == ktyp && mt.Elem == etyp {
|
||||
// ti, _ := lookupCache.LoadOrStore(ckey, toRType(tt))
|
||||
// return ti.(Type)
|
||||
// }
|
||||
// }
|
||||
|
||||
// Make a map type.
|
||||
// Note: flag values must match those used in the TMAP case
|
||||
// in ../cmd/compile/internal/reflectdata/reflect.go:writeType.
|
||||
var imap any = (map[unsafe.Pointer]unsafe.Pointer)(nil)
|
||||
mt := **(**mapType)(unsafe.Pointer(&imap))
|
||||
mt.Str_ = s
|
||||
mt.TFlag = 0
|
||||
mt.Hash = fnv1(etyp.Hash, 'm', byte(ktyp.Hash>>24), byte(ktyp.Hash>>16), byte(ktyp.Hash>>8), byte(ktyp.Hash))
|
||||
mt.Key = ktyp
|
||||
mt.Elem = etyp
|
||||
mt.Bucket = bucketOf(ktyp, etyp)
|
||||
mt.Hasher = func(p unsafe.Pointer, seed uintptr) uintptr {
|
||||
return typehash(ktyp, p, seed)
|
||||
}
|
||||
mt.Flags = 0
|
||||
if ktyp.Size_ > maxKeySize {
|
||||
mt.KeySize = uint8(goarch.PtrSize)
|
||||
mt.Flags |= 1 // indirect key
|
||||
} else {
|
||||
mt.KeySize = uint8(ktyp.Size_)
|
||||
}
|
||||
if etyp.Size_ > maxValSize {
|
||||
mt.ValueSize = uint8(goarch.PtrSize)
|
||||
mt.Flags |= 2 // indirect value
|
||||
} else {
|
||||
mt.MapType.ValueSize = uint8(etyp.Size_)
|
||||
}
|
||||
mt.MapType.BucketSize = uint16(mt.Bucket.Size_)
|
||||
if isReflexive(ktyp) {
|
||||
mt.Flags |= 4
|
||||
}
|
||||
if needKeyUpdate(ktyp) {
|
||||
mt.Flags |= 8
|
||||
}
|
||||
if hashMightPanic(ktyp) {
|
||||
mt.Flags |= 16
|
||||
}
|
||||
mt.PtrToThis_ = nil
|
||||
|
||||
ti, _ := lookupCache.LoadOrStore(ckey, toRType(&mt.Type))
|
||||
return ti.(Type)
|
||||
}
|
||||
|
||||
// isReflexive reports whether the == operation on the type is reflexive.
|
||||
// That is, x == x for all values x of type t.
|
||||
func isReflexive(t *abi.Type) bool {
|
||||
switch Kind(t.Kind()) {
|
||||
case Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Chan, Pointer, String, UnsafePointer:
|
||||
return true
|
||||
case Float32, Float64, Complex64, Complex128, Interface:
|
||||
return false
|
||||
case Array:
|
||||
tt := (*arrayType)(unsafe.Pointer(t))
|
||||
return isReflexive(tt.Elem)
|
||||
case Struct:
|
||||
tt := (*structType)(unsafe.Pointer(t))
|
||||
for _, f := range tt.Fields {
|
||||
if !isReflexive(f.Typ) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
default:
|
||||
// Func, Map, Slice, Invalid
|
||||
panic("isReflexive called on non-key type " + stringFor(t))
|
||||
}
|
||||
}
|
||||
|
||||
// needKeyUpdate reports whether map overwrites require the key to be copied.
|
||||
func needKeyUpdate(t *abi.Type) bool {
|
||||
switch Kind(t.Kind()) {
|
||||
case Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Chan, Pointer, UnsafePointer:
|
||||
return false
|
||||
case Float32, Float64, Complex64, Complex128, Interface, String:
|
||||
// Float keys can be updated from +0 to -0.
|
||||
// String keys can be updated to use a smaller backing store.
|
||||
// Interfaces might have floats of strings in them.
|
||||
return true
|
||||
case Array:
|
||||
tt := (*arrayType)(unsafe.Pointer(t))
|
||||
return needKeyUpdate(tt.Elem)
|
||||
case Struct:
|
||||
tt := (*structType)(unsafe.Pointer(t))
|
||||
for _, f := range tt.Fields {
|
||||
if needKeyUpdate(f.Typ) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
default:
|
||||
// Func, Map, Slice, Invalid
|
||||
panic("needKeyUpdate called on non-key type " + stringFor(t))
|
||||
}
|
||||
}
|
||||
|
||||
// hashMightPanic reports whether the hash of a map key of type t might panic.
|
||||
func hashMightPanic(t *abi.Type) bool {
|
||||
switch Kind(t.Kind()) {
|
||||
case Interface:
|
||||
return true
|
||||
case Array:
|
||||
tt := (*arrayType)(unsafe.Pointer(t))
|
||||
return hashMightPanic(tt.Elem)
|
||||
case Struct:
|
||||
tt := (*structType)(unsafe.Pointer(t))
|
||||
for _, f := range tt.Fields {
|
||||
if hashMightPanic(f.Typ) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure these routines stay in sync with ../runtime/map.go!
|
||||
// These types exist only for GC, so we only fill out GC relevant info.
|
||||
// Currently, that's just size and the GC program. We also fill in string
|
||||
// for possible debugging use.
|
||||
const (
|
||||
bucketSize uintptr = abi.MapBucketCount
|
||||
maxKeySize uintptr = abi.MapMaxKeyBytes
|
||||
maxValSize uintptr = abi.MapMaxElemBytes
|
||||
)
|
||||
|
||||
func bucketOf(ktyp, etyp *abi.Type) *abi.Type {
|
||||
if ktyp.Size_ > maxKeySize {
|
||||
ktyp = ptrTo(ktyp)
|
||||
}
|
||||
if etyp.Size_ > maxValSize {
|
||||
etyp = ptrTo(etyp)
|
||||
}
|
||||
|
||||
// Prepare GC data if any.
|
||||
// A bucket is at most bucketSize*(1+maxKeySize+maxValSize)+ptrSize bytes,
|
||||
// or 2064 bytes, or 258 pointer-size words, or 33 bytes of pointer bitmap.
|
||||
// Note that since the key and value are known to be <= 128 bytes,
|
||||
// they're guaranteed to have bitmaps instead of GC programs.
|
||||
var gcdata *byte
|
||||
var ptrdata uintptr
|
||||
|
||||
size := bucketSize*(1+ktyp.Size_+etyp.Size_) + goarch.PtrSize
|
||||
if size&uintptr(ktyp.Align_-1) != 0 || size&uintptr(etyp.Align_-1) != 0 {
|
||||
panic("reflect: bad size computation in MapOf")
|
||||
}
|
||||
|
||||
if ktyp.PtrBytes != 0 || etyp.PtrBytes != 0 {
|
||||
nptr := (bucketSize*(1+ktyp.Size_+etyp.Size_) + goarch.PtrSize) / goarch.PtrSize
|
||||
n := (nptr + 7) / 8
|
||||
|
||||
// Runtime needs pointer masks to be a multiple of uintptr in size.
|
||||
n = (n + goarch.PtrSize - 1) &^ (goarch.PtrSize - 1)
|
||||
mask := make([]byte, n)
|
||||
base := bucketSize / goarch.PtrSize
|
||||
|
||||
if ktyp.PtrBytes != 0 {
|
||||
emitGCMask(mask, base, ktyp, bucketSize)
|
||||
}
|
||||
base += bucketSize * ktyp.Size_ / goarch.PtrSize
|
||||
|
||||
if etyp.PtrBytes != 0 {
|
||||
emitGCMask(mask, base, etyp, bucketSize)
|
||||
}
|
||||
base += bucketSize * etyp.Size_ / goarch.PtrSize
|
||||
|
||||
word := base
|
||||
mask[word/8] |= 1 << (word % 8)
|
||||
gcdata = &mask[0]
|
||||
ptrdata = (word + 1) * goarch.PtrSize
|
||||
|
||||
// overflow word must be last
|
||||
if ptrdata != size {
|
||||
panic("reflect: bad layout computation in MapOf")
|
||||
}
|
||||
}
|
||||
|
||||
b := &abi.Type{
|
||||
Align_: goarch.PtrSize,
|
||||
Size_: size,
|
||||
Kind_: uint8(Struct),
|
||||
PtrBytes: ptrdata,
|
||||
GCData: gcdata,
|
||||
}
|
||||
b.Str_ = "bucket(" + stringFor(ktyp) + "," + stringFor(etyp) + ")"
|
||||
return b
|
||||
}
|
||||
|
||||
func (t *rtype) gcSlice(begin, end uintptr) []byte {
|
||||
return (*[1 << 30]byte)(unsafe.Pointer(t.t.GCData))[begin:end:end]
|
||||
}
|
||||
|
||||
// emitGCMask writes the GC mask for [n]typ into out, starting at bit
|
||||
// offset base.
|
||||
func emitGCMask(out []byte, base uintptr, typ *abi.Type, n uintptr) {
|
||||
// if typ.Kind_&kindGCProg != 0 {
|
||||
// panic("reflect: unexpected GC program")
|
||||
// }
|
||||
// ptrs := typ.PtrBytes / goarch.PtrSize
|
||||
// words := typ.Size_ / goarch.PtrSize
|
||||
// mask := typ.GcSlice(0, (ptrs+7)/8)
|
||||
// for j := uintptr(0); j < ptrs; j++ {
|
||||
// if (mask[j/8]>>(j%8))&1 != 0 {
|
||||
// for i := uintptr(0); i < n; i++ {
|
||||
// k := base + i*words + j
|
||||
// out[k/8] |= 1 << (k % 8)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -1251,29 +1251,28 @@ func (v Value) SetCap(n int) {
|
||||
// As in Go, key's elem must be assignable to the map's key type,
|
||||
// and elem's value must be assignable to the map's elem type.
|
||||
func (v Value) SetMapIndex(key, elem Value) {
|
||||
/* TODO(xsw):
|
||||
v.mustBe(Map)
|
||||
v.mustBeExported()
|
||||
key.mustBeExported()
|
||||
tt := (*mapType)(unsafe.Pointer(v.typ()))
|
||||
|
||||
if (tt.Key == stringType || key.kind() == String) && tt.Key == key.typ() && tt.Elem.Size() <= maxValSize {
|
||||
k := *(*string)(key.ptr)
|
||||
if elem.typ() == nil {
|
||||
mapdelete_faststr(v.typ(), v.pointer(), k)
|
||||
return
|
||||
}
|
||||
elem.mustBeExported()
|
||||
elem = elem.assignTo("reflect.Value.SetMapIndex", tt.Elem, nil)
|
||||
var e unsafe.Pointer
|
||||
if elem.flag&flagIndir != 0 {
|
||||
e = elem.ptr
|
||||
} else {
|
||||
e = unsafe.Pointer(&elem.ptr)
|
||||
}
|
||||
mapassign_faststr(v.typ(), v.pointer(), k, e)
|
||||
return
|
||||
}
|
||||
// if (tt.Key == stringType || key.kind() == String) && tt.Key == key.typ() && tt.Elem.Size() <= maxValSize {
|
||||
// k := *(*string)(key.ptr)
|
||||
// if elem.typ() == nil {
|
||||
// mapdelete_faststr(v.typ(), v.pointer(), k)
|
||||
// return
|
||||
// }
|
||||
// elem.mustBeExported()
|
||||
// elem = elem.assignTo("reflect.Value.SetMapIndex", tt.Elem, nil)
|
||||
// var e unsafe.Pointer
|
||||
// if elem.flag&flagIndir != 0 {
|
||||
// e = elem.ptr
|
||||
// } else {
|
||||
// e = unsafe.Pointer(&elem.ptr)
|
||||
// }
|
||||
// mapassign_faststr(v.typ(), v.pointer(), k, e)
|
||||
// return
|
||||
// }
|
||||
|
||||
key = key.assignTo("reflect.Value.SetMapIndex", tt.Key, nil)
|
||||
var k unsafe.Pointer
|
||||
@@ -1295,8 +1294,6 @@ func (v Value) SetMapIndex(key, elem Value) {
|
||||
e = unsafe.Pointer(&elem.ptr)
|
||||
}
|
||||
mapassign(v.typ(), v.pointer(), k, e)
|
||||
*/
|
||||
panic("todo: reflect.Value.SetMapIndex")
|
||||
}
|
||||
|
||||
// SetUint sets v's underlying value to x.
|
||||
@@ -2270,296 +2267,277 @@ func (v Value) call(op string, in []Value) (out []Value) {
|
||||
return
|
||||
}
|
||||
|
||||
// var callGC bool // for testing; see TestCallMethodJump and TestCallArgLive
|
||||
var stringType = rtypeOf("")
|
||||
|
||||
// const debugReflectCall = false
|
||||
// MapIndex returns the value associated with key in the map v.
|
||||
// It panics if v's Kind is not Map.
|
||||
// It returns the zero Value if key is not found in the map or if v represents a nil map.
|
||||
// As in Go, the key's value must be assignable to the map's key type.
|
||||
func (v Value) MapIndex(key Value) Value {
|
||||
v.mustBe(Map)
|
||||
tt := (*mapType)(unsafe.Pointer(v.typ()))
|
||||
|
||||
// func (v Value) call(op string, in []Value) []Value {
|
||||
// // Get function pointer, type.
|
||||
// t := (*funcType)(unsafe.Pointer(v.typ()))
|
||||
// var (
|
||||
// fn unsafe.Pointer
|
||||
// rcvr Value
|
||||
// rcvrtype *abi.Type
|
||||
// )
|
||||
// if v.flag&flagMethod != 0 {
|
||||
// rcvr = v
|
||||
// rcvrtype, t, fn = methodReceiver(op, v, int(v.flag)>>flagMethodShift)
|
||||
// } else if v.flag&flagIndir != 0 {
|
||||
// fn = *(*unsafe.Pointer)(v.ptr)
|
||||
// } else {
|
||||
// fn = v.ptr
|
||||
// }
|
||||
// Do not require key to be exported, so that DeepEqual
|
||||
// and other programs can use all the keys returned by
|
||||
// MapKeys as arguments to MapIndex. If either the map
|
||||
// or the key is unexported, though, the result will be
|
||||
// considered unexported. This is consistent with the
|
||||
// behavior for structs, which allow read but not write
|
||||
// of unexported fields.
|
||||
|
||||
// if fn == nil {
|
||||
// panic("reflect.Value.Call: call of nil function")
|
||||
// }
|
||||
var e unsafe.Pointer
|
||||
// if (tt.Key == stringType || key.kind() == String) && tt.Key == key.typ() && tt.Elem.Size() <= maxValSize {
|
||||
// k := *(*string)(key.ptr)
|
||||
// e = mapaccess_faststr(v.typ(), v.pointer(), k)
|
||||
// } else {
|
||||
key = key.assignTo("reflect.Value.MapIndex", tt.Key, nil)
|
||||
var k unsafe.Pointer
|
||||
if key.flag&flagIndir != 0 {
|
||||
k = key.ptr
|
||||
} else {
|
||||
k = unsafe.Pointer(&key.ptr)
|
||||
}
|
||||
var ok bool
|
||||
e, ok = mapaccess(v.typ(), v.pointer(), k)
|
||||
if !ok {
|
||||
return Value{}
|
||||
}
|
||||
typ := tt.Elem
|
||||
fl := (v.flag | key.flag).ro()
|
||||
fl |= flag(typ.Kind())
|
||||
return copyVal(typ, fl, e)
|
||||
}
|
||||
|
||||
// isSlice := op == "CallSlice"
|
||||
// n := t.NumIn()
|
||||
// isVariadic := t.IsVariadic()
|
||||
// if isSlice {
|
||||
// if !isVariadic {
|
||||
// panic("reflect: CallSlice of non-variadic function")
|
||||
// }
|
||||
// if len(in) < n {
|
||||
// panic("reflect: CallSlice with too few input arguments")
|
||||
// }
|
||||
// if len(in) > n {
|
||||
// panic("reflect: CallSlice with too many input arguments")
|
||||
// }
|
||||
// } else {
|
||||
// if isVariadic {
|
||||
// n--
|
||||
// }
|
||||
// if len(in) < n {
|
||||
// panic("reflect: Call with too few input arguments")
|
||||
// }
|
||||
// if !isVariadic && len(in) > n {
|
||||
// panic("reflect: Call with too many input arguments")
|
||||
// }
|
||||
// }
|
||||
// for _, x := range in {
|
||||
// if x.Kind() == Invalid {
|
||||
// panic("reflect: " + op + " using zero Value argument")
|
||||
// }
|
||||
// }
|
||||
// for i := 0; i < n; i++ {
|
||||
// if xt, targ := in[i].Type(), t.In(i); !xt.AssignableTo(toRType(targ)) {
|
||||
// panic("reflect: " + op + " using " + xt.String() + " as type " + stringFor(targ))
|
||||
// }
|
||||
// }
|
||||
// if !isSlice && isVariadic {
|
||||
// // prepare slice for remaining values
|
||||
// m := len(in) - n
|
||||
// slice := MakeSlice(toRType(t.In(n)), m, m)
|
||||
// elem := toRType(t.In(n)).Elem() // FIXME cast to slice type and Elem()
|
||||
// for i := 0; i < m; i++ {
|
||||
// x := in[n+i]
|
||||
// if xt := x.Type(); !xt.AssignableTo(elem) {
|
||||
// panic("reflect: cannot use " + xt.String() + " as type " + elem.String() + " in " + op)
|
||||
// }
|
||||
// slice.Index(i).Set(x)
|
||||
// }
|
||||
// origIn := in
|
||||
// in = make([]Value, n+1)
|
||||
// copy(in[:n], origIn)
|
||||
// in[n] = slice
|
||||
// }
|
||||
// MapKeys returns a slice containing all the keys present in the map,
|
||||
// in unspecified order.
|
||||
// It panics if v's Kind is not Map.
|
||||
// It returns an empty slice if v represents a nil map.
|
||||
func (v Value) MapKeys() []Value {
|
||||
v.mustBe(Map)
|
||||
tt := (*mapType)(unsafe.Pointer(v.typ()))
|
||||
keyType := tt.Key
|
||||
|
||||
// nin := len(in)
|
||||
// if nin != t.NumIn() {
|
||||
// panic("reflect.Value.Call: wrong argument count")
|
||||
// }
|
||||
// nout := t.NumOut()
|
||||
fl := v.flag.ro() | flag(keyType.Kind())
|
||||
|
||||
// // Register argument space.
|
||||
// var regArgs abi.RegArgs
|
||||
m := v.pointer()
|
||||
mlen := int(0)
|
||||
if m != nil {
|
||||
mlen = maplen(m)
|
||||
}
|
||||
var it hiter
|
||||
mapiterinit(v.typ(), m, &it)
|
||||
a := make([]Value, mlen)
|
||||
var i int
|
||||
for i = 0; i < len(a); i++ {
|
||||
key := mapiterkey(&it)
|
||||
if key == nil {
|
||||
// Someone deleted an entry from the map since we
|
||||
// called maplen above. It's a data race, but nothing
|
||||
// we can do about it.
|
||||
break
|
||||
}
|
||||
a[i] = copyVal(keyType, fl, key)
|
||||
mapiternext(&it)
|
||||
}
|
||||
return a[:i]
|
||||
}
|
||||
|
||||
// // Compute frame type.
|
||||
// frametype, framePool, abid := funcLayout(t, rcvrtype)
|
||||
// hiter's structure matches runtime.hiter's structure.
|
||||
// Having a clone here allows us to embed a map iterator
|
||||
// inside type MapIter so that MapIters can be re-used
|
||||
// without doing any allocations.
|
||||
type hiter struct {
|
||||
key unsafe.Pointer
|
||||
elem unsafe.Pointer
|
||||
t unsafe.Pointer
|
||||
h unsafe.Pointer
|
||||
buckets unsafe.Pointer
|
||||
bptr unsafe.Pointer
|
||||
overflow *[]unsafe.Pointer
|
||||
oldoverflow *[]unsafe.Pointer
|
||||
startBucket uintptr
|
||||
offset uint8
|
||||
wrapped bool
|
||||
B uint8
|
||||
i uint8
|
||||
bucket uintptr
|
||||
checkBucket uintptr
|
||||
}
|
||||
|
||||
// // Allocate a chunk of memory for frame if needed.
|
||||
// var stackArgs unsafe.Pointer
|
||||
// if frametype.Size() != 0 {
|
||||
// if nout == 0 {
|
||||
// stackArgs = framePool.Get().(unsafe.Pointer)
|
||||
// } else {
|
||||
// // Can't use pool if the function has return values.
|
||||
// // We will leak pointer to args in ret, so its lifetime is not scoped.
|
||||
// stackArgs = unsafe_New(frametype)
|
||||
// }
|
||||
// }
|
||||
// frameSize := frametype.Size()
|
||||
func (h *hiter) initialized() bool {
|
||||
return h.t != nil
|
||||
}
|
||||
|
||||
// if debugReflectCall {
|
||||
// println("reflect.call", stringFor(&t.Type))
|
||||
// abid.dump()
|
||||
// }
|
||||
// A MapIter is an iterator for ranging over a map.
|
||||
// See Value.MapRange.
|
||||
type MapIter struct {
|
||||
m Value
|
||||
hiter hiter
|
||||
}
|
||||
|
||||
// // Copy inputs into args.
|
||||
// Key returns the key of iter's current map entry.
|
||||
func (iter *MapIter) Key() Value {
|
||||
if !iter.hiter.initialized() {
|
||||
panic("MapIter.Key called before Next")
|
||||
}
|
||||
iterkey := mapiterkey(&iter.hiter)
|
||||
if iterkey == nil {
|
||||
panic("MapIter.Key called on exhausted iterator")
|
||||
}
|
||||
|
||||
// // Handle receiver.
|
||||
// inStart := 0
|
||||
// if rcvrtype != nil {
|
||||
// // Guaranteed to only be one word in size,
|
||||
// // so it will only take up exactly 1 abiStep (either
|
||||
// // in a register or on the stack).
|
||||
// switch st := abid.call.steps[0]; st.kind {
|
||||
// case abiStepStack:
|
||||
// storeRcvr(rcvr, stackArgs)
|
||||
// case abiStepPointer:
|
||||
// storeRcvr(rcvr, unsafe.Pointer(®Args.Ptrs[st.ireg]))
|
||||
// fallthrough
|
||||
// case abiStepIntReg:
|
||||
// storeRcvr(rcvr, unsafe.Pointer(®Args.Ints[st.ireg]))
|
||||
// case abiStepFloatReg:
|
||||
// storeRcvr(rcvr, unsafe.Pointer(®Args.Floats[st.freg]))
|
||||
// default:
|
||||
// panic("unknown ABI parameter kind")
|
||||
// }
|
||||
// inStart = 1
|
||||
// }
|
||||
t := (*mapType)(unsafe.Pointer(iter.m.typ()))
|
||||
ktype := t.Key
|
||||
return copyVal(ktype, iter.m.flag.ro()|flag(ktype.Kind()), iterkey)
|
||||
}
|
||||
|
||||
// // Handle arguments.
|
||||
// for i, v := range in {
|
||||
// v.mustBeExported()
|
||||
// targ := toRType(t.In(i))
|
||||
// // TODO(mknyszek): Figure out if it's possible to get some
|
||||
// // scratch space for this assignment check. Previously, it
|
||||
// // was possible to use space in the argument frame.
|
||||
// v = v.assignTo("reflect.Value.Call", &targ.t, nil)
|
||||
// stepsLoop:
|
||||
// for _, st := range abid.call.stepsForValue(i + inStart) {
|
||||
// switch st.kind {
|
||||
// case abiStepStack:
|
||||
// // Copy values to the "stack."
|
||||
// addr := add(stackArgs, st.stkOff, "precomputed stack arg offset")
|
||||
// if v.flag&flagIndir != 0 {
|
||||
// typedmemmove(&targ.t, addr, v.ptr)
|
||||
// } else {
|
||||
// *(*unsafe.Pointer)(addr) = v.ptr
|
||||
// }
|
||||
// // There's only one step for a stack-allocated value.
|
||||
// break stepsLoop
|
||||
// case abiStepIntReg, abiStepPointer:
|
||||
// // Copy values to "integer registers."
|
||||
// if v.flag&flagIndir != 0 {
|
||||
// offset := add(v.ptr, st.offset, "precomputed value offset")
|
||||
// if st.kind == abiStepPointer {
|
||||
// // Duplicate this pointer in the pointer area of the
|
||||
// // register space. Otherwise, there's the potential for
|
||||
// // this to be the last reference to v.ptr.
|
||||
// regArgs.Ptrs[st.ireg] = *(*unsafe.Pointer)(offset)
|
||||
// }
|
||||
// intToReg(®Args, st.ireg, st.size, offset)
|
||||
// } else {
|
||||
// if st.kind == abiStepPointer {
|
||||
// // See the comment in abiStepPointer case above.
|
||||
// regArgs.Ptrs[st.ireg] = v.ptr
|
||||
// }
|
||||
// regArgs.Ints[st.ireg] = uintptr(v.ptr)
|
||||
// }
|
||||
// case abiStepFloatReg:
|
||||
// // Copy values to "float registers."
|
||||
// if v.flag&flagIndir == 0 {
|
||||
// panic("attempted to copy pointer to FP register")
|
||||
// }
|
||||
// offset := add(v.ptr, st.offset, "precomputed value offset")
|
||||
// floatToReg(®Args, st.freg, st.size, offset)
|
||||
// default:
|
||||
// panic("unknown ABI part kind")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // TODO(mknyszek): Remove this when we no longer have
|
||||
// // caller reserved spill space.
|
||||
// frameSize = align(frameSize, goarch.PtrSize)
|
||||
// frameSize += abid.spill
|
||||
// SetIterKey assigns to v the key of iter's current map entry.
|
||||
// It is equivalent to v.Set(iter.Key()), but it avoids allocating a new Value.
|
||||
// As in Go, the key must be assignable to v's type and
|
||||
// must not be derived from an unexported field.
|
||||
func (v Value) SetIterKey(iter *MapIter) {
|
||||
if !iter.hiter.initialized() {
|
||||
panic("reflect: Value.SetIterKey called before Next")
|
||||
}
|
||||
iterkey := mapiterkey(&iter.hiter)
|
||||
if iterkey == nil {
|
||||
panic("reflect: Value.SetIterKey called on exhausted iterator")
|
||||
}
|
||||
|
||||
// // Mark pointers in registers for the return path.
|
||||
// regArgs.ReturnIsPtr = abid.outRegPtrs
|
||||
v.mustBeAssignable()
|
||||
var target unsafe.Pointer
|
||||
if v.kind() == Interface {
|
||||
target = v.ptr
|
||||
}
|
||||
|
||||
// if debugReflectCall {
|
||||
// regArgs.Dump()
|
||||
// }
|
||||
t := (*mapType)(unsafe.Pointer(iter.m.typ()))
|
||||
ktype := t.Key
|
||||
|
||||
// // For testing; see TestCallArgLive.
|
||||
// if callGC {
|
||||
// runtime.GC()
|
||||
// }
|
||||
iter.m.mustBeExported() // do not let unexported m leak
|
||||
key := Value{ktype, iterkey, iter.m.flag | flag(ktype.Kind()) | flagIndir}
|
||||
key = key.assignTo("reflect.MapIter.SetKey", v.typ(), target)
|
||||
typedmemmove(v.typ(), v.ptr, key.ptr)
|
||||
}
|
||||
|
||||
// // Call.
|
||||
// call(frametype, fn, stackArgs, uint32(frametype.Size()), uint32(abid.retOffset), uint32(frameSize), ®Args)
|
||||
// Value returns the value of iter's current map entry.
|
||||
func (iter *MapIter) Value() Value {
|
||||
if !iter.hiter.initialized() {
|
||||
panic("MapIter.Value called before Next")
|
||||
}
|
||||
iterelem := mapiterelem(&iter.hiter)
|
||||
if iterelem == nil {
|
||||
panic("MapIter.Value called on exhausted iterator")
|
||||
}
|
||||
|
||||
// // For testing; see TestCallMethodJump.
|
||||
// if callGC {
|
||||
// runtime.GC()
|
||||
// }
|
||||
t := (*mapType)(unsafe.Pointer(iter.m.typ()))
|
||||
vtype := t.Elem
|
||||
return copyVal(vtype, iter.m.flag.ro()|flag(vtype.Kind()), iterelem)
|
||||
}
|
||||
|
||||
// var ret []Value
|
||||
// if nout == 0 {
|
||||
// if stackArgs != nil {
|
||||
// typedmemclr(frametype, stackArgs)
|
||||
// framePool.Put(stackArgs)
|
||||
// }
|
||||
// } else {
|
||||
// if stackArgs != nil {
|
||||
// // Zero the now unused input area of args,
|
||||
// // because the Values returned by this function contain pointers to the args object,
|
||||
// // and will thus keep the args object alive indefinitely.
|
||||
// typedmemclrpartial(frametype, stackArgs, 0, abid.retOffset)
|
||||
// }
|
||||
// SetIterValue assigns to v the value of iter's current map entry.
|
||||
// It is equivalent to v.Set(iter.Value()), but it avoids allocating a new Value.
|
||||
// As in Go, the value must be assignable to v's type and
|
||||
// must not be derived from an unexported field.
|
||||
func (v Value) SetIterValue(iter *MapIter) {
|
||||
if !iter.hiter.initialized() {
|
||||
panic("reflect: Value.SetIterValue called before Next")
|
||||
}
|
||||
iterelem := mapiterelem(&iter.hiter)
|
||||
if iterelem == nil {
|
||||
panic("reflect: Value.SetIterValue called on exhausted iterator")
|
||||
}
|
||||
|
||||
// // Wrap Values around return values in args.
|
||||
// ret = make([]Value, nout)
|
||||
// for i := 0; i < nout; i++ {
|
||||
// tv := t.Out(i)
|
||||
// if tv.Size() == 0 {
|
||||
// // For zero-sized return value, args+off may point to the next object.
|
||||
// // In this case, return the zero value instead.
|
||||
// ret[i] = Zero(toRType(tv))
|
||||
// continue
|
||||
// }
|
||||
// steps := abid.ret.stepsForValue(i)
|
||||
// if st := steps[0]; st.kind == abiStepStack {
|
||||
// // This value is on the stack. If part of a value is stack
|
||||
// // allocated, the entire value is according to the ABI. So
|
||||
// // just make an indirection into the allocated frame.
|
||||
// fl := flagIndir | flag(tv.Kind())
|
||||
// ret[i] = Value{tv, add(stackArgs, st.stkOff, "tv.Size() != 0"), fl}
|
||||
// // Note: this does introduce false sharing between results -
|
||||
// // if any result is live, they are all live.
|
||||
// // (And the space for the args is live as well, but as we've
|
||||
// // cleared that space it isn't as big a deal.)
|
||||
// continue
|
||||
// }
|
||||
v.mustBeAssignable()
|
||||
var target unsafe.Pointer
|
||||
if v.kind() == Interface {
|
||||
target = v.ptr
|
||||
}
|
||||
|
||||
// // Handle pointers passed in registers.
|
||||
// if !ifaceIndir(tv) {
|
||||
// // Pointer-valued data gets put directly
|
||||
// // into v.ptr.
|
||||
// if steps[0].kind != abiStepPointer {
|
||||
// print("kind=", steps[0].kind, ", type=", stringFor(tv), "\n")
|
||||
// panic("mismatch between ABI description and types")
|
||||
// }
|
||||
// ret[i] = Value{tv, regArgs.Ptrs[steps[0].ireg], flag(tv.Kind())}
|
||||
// continue
|
||||
// }
|
||||
t := (*mapType)(unsafe.Pointer(iter.m.typ()))
|
||||
vtype := t.Elem
|
||||
|
||||
// // All that's left is values passed in registers that we need to
|
||||
// // create space for and copy values back into.
|
||||
// //
|
||||
// // TODO(mknyszek): We make a new allocation for each register-allocated
|
||||
// // value, but previously we could always point into the heap-allocated
|
||||
// // stack frame. This is a regression that could be fixed by adding
|
||||
// // additional space to the allocated stack frame and storing the
|
||||
// // register-allocated return values into the allocated stack frame and
|
||||
// // referring there in the resulting Value.
|
||||
// s := unsafe_New(tv)
|
||||
// for _, st := range steps {
|
||||
// switch st.kind {
|
||||
// case abiStepIntReg:
|
||||
// offset := add(s, st.offset, "precomputed value offset")
|
||||
// intFromReg(®Args, st.ireg, st.size, offset)
|
||||
// case abiStepPointer:
|
||||
// s := add(s, st.offset, "precomputed value offset")
|
||||
// *((*unsafe.Pointer)(s)) = regArgs.Ptrs[st.ireg]
|
||||
// case abiStepFloatReg:
|
||||
// offset := add(s, st.offset, "precomputed value offset")
|
||||
// floatFromReg(®Args, st.freg, st.size, offset)
|
||||
// case abiStepStack:
|
||||
// panic("register-based return value has stack component")
|
||||
// default:
|
||||
// panic("unknown ABI part kind")
|
||||
// }
|
||||
// }
|
||||
// ret[i] = Value{tv, s, flagIndir | flag(tv.Kind())}
|
||||
// }
|
||||
// }
|
||||
iter.m.mustBeExported() // do not let unexported m leak
|
||||
elem := Value{vtype, iterelem, iter.m.flag | flag(vtype.Kind()) | flagIndir}
|
||||
elem = elem.assignTo("reflect.MapIter.SetValue", v.typ(), target)
|
||||
typedmemmove(v.typ(), v.ptr, elem.ptr)
|
||||
}
|
||||
|
||||
// return ret
|
||||
// Next advances the map iterator and reports whether there is another
|
||||
// entry. It returns false when iter is exhausted; subsequent
|
||||
// calls to Key, Value, or Next will panic.
|
||||
func (iter *MapIter) Next() bool {
|
||||
if !iter.m.IsValid() {
|
||||
panic("MapIter.Next called on an iterator that does not have an associated map Value")
|
||||
}
|
||||
if !iter.hiter.initialized() {
|
||||
mapiterinit(iter.m.typ(), iter.m.pointer(), &iter.hiter)
|
||||
} else {
|
||||
if mapiterkey(&iter.hiter) == nil {
|
||||
panic("MapIter.Next called on exhausted iterator")
|
||||
}
|
||||
mapiternext(&iter.hiter)
|
||||
}
|
||||
return mapiterkey(&iter.hiter) != nil
|
||||
}
|
||||
|
||||
// Reset modifies iter to iterate over v.
|
||||
// It panics if v's Kind is not Map and v is not the zero Value.
|
||||
// Reset(Value{}) causes iter to not to refer to any map,
|
||||
// which may allow the previously iterated-over map to be garbage collected.
|
||||
func (iter *MapIter) Reset(v Value) {
|
||||
if v.IsValid() {
|
||||
v.mustBe(Map)
|
||||
}
|
||||
iter.m = v
|
||||
iter.hiter = hiter{}
|
||||
}
|
||||
|
||||
// MapRange returns a range iterator for a map.
|
||||
// It panics if v's Kind is not Map.
|
||||
//
|
||||
// Call Next to advance the iterator, and Key/Value to access each entry.
|
||||
// Next returns false when the iterator is exhausted.
|
||||
// MapRange follows the same iteration semantics as a range statement.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// iter := reflect.ValueOf(m).MapRange()
|
||||
// for iter.Next() {
|
||||
// k := iter.Key()
|
||||
// v := iter.Value()
|
||||
// ...
|
||||
// }
|
||||
func (v Value) MapRange() *MapIter {
|
||||
// This is inlinable to take advantage of "function outlining".
|
||||
// The allocation of MapIter can be stack allocated if the caller
|
||||
// does not allow it to escape.
|
||||
// See https://blog.filippo.io/efficient-go-apis-with-the-inliner/
|
||||
if v.kind() != Map {
|
||||
v.panicNotMap()
|
||||
}
|
||||
return &MapIter{m: v}
|
||||
}
|
||||
|
||||
// Force slow panicking path not inlined, so it won't add to the
|
||||
// inlining budget of the caller.
|
||||
// TODO undo when the inliner is no longer bottom-up only.
|
||||
//
|
||||
//go:noinline
|
||||
func (f flag) panicNotMap() {
|
||||
f.mustBe(Map)
|
||||
}
|
||||
|
||||
// copyVal returns a Value containing the map key or value at ptr,
|
||||
// allocating a new variable as needed.
|
||||
func copyVal(typ *abi.Type, fl flag, ptr unsafe.Pointer) Value {
|
||||
if typ.IfaceIndir() {
|
||||
// Copy result so future changes to the map
|
||||
// won't change the underlying value.
|
||||
c := unsafe_New(typ)
|
||||
typedmemmove(typ, c, ptr)
|
||||
return Value{typ, c, fl | flagIndir}
|
||||
}
|
||||
return Value{typ, *(*unsafe.Pointer)(ptr), fl}
|
||||
}
|
||||
|
||||
// methodReceiver returns information about the receiver
|
||||
// described by v. The Value v may or may not have the
|
||||
@@ -2609,9 +2587,60 @@ func chancap(ch unsafe.Pointer) int
|
||||
//go:linkname chanlen github.com/goplus/llgo/internal/runtime.ChanLen
|
||||
func chanlen(ch unsafe.Pointer) int
|
||||
|
||||
//go:linkname makemap github.com/goplus/llgo/internal/runtime.MakeMap
|
||||
func makemap(t *abi.Type, cap int) (m unsafe.Pointer)
|
||||
|
||||
//go:linkname maplen github.com/goplus/llgo/internal/runtime.MapLen
|
||||
func maplen(ch unsafe.Pointer) int
|
||||
|
||||
//go:linkname mapaccess github.com/goplus/llgo/internal/runtime.MapAccess2
|
||||
func mapaccess(t *abi.Type, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer, ok bool)
|
||||
|
||||
//go:linkname mapassign0 github.com/goplus/llgo/internal/runtime.MapAssign
|
||||
func mapassign0(t *abi.Type, m unsafe.Pointer, key unsafe.Pointer) unsafe.Pointer
|
||||
|
||||
func mapassign(t *abi.Type, m unsafe.Pointer, key, val unsafe.Pointer) {
|
||||
contentEscapes(key)
|
||||
contentEscapes(val)
|
||||
p := mapassign0(t, m, key)
|
||||
runtime.Typedmemmove(t.Elem(), p, val)
|
||||
}
|
||||
|
||||
// //go:noescape
|
||||
// func mapassign_faststr0(t *abi.Type, m unsafe.Pointer, key string, val unsafe.Pointer)
|
||||
|
||||
// func mapassign_faststr(t *abi.Type, m unsafe.Pointer, key string, val unsafe.Pointer) {
|
||||
// contentEscapes((*unsafeheader.String)(unsafe.Pointer(&key)).Data)
|
||||
// contentEscapes(val)
|
||||
// mapassign_faststr0(t, m, key, val)
|
||||
// }
|
||||
|
||||
//go:linkname mapdelete github.com/goplus/llgo/internal/runtime.MapDelete
|
||||
func mapdelete(t *abi.Type, m unsafe.Pointer, key unsafe.Pointer)
|
||||
|
||||
//go:noescape
|
||||
// func mapdelete_faststr(t *abi.Type, m unsafe.Pointer, key string)
|
||||
|
||||
//go:linkname mapiterinit github.com/goplus/llgo/internal/runtime.mapiterinit
|
||||
func mapiterinit(t *abi.Type, m unsafe.Pointer, it *hiter)
|
||||
|
||||
func mapiterkey(it *hiter) (key unsafe.Pointer) {
|
||||
return it.key
|
||||
}
|
||||
|
||||
func mapiterelem(it *hiter) (elem unsafe.Pointer) {
|
||||
return it.elem
|
||||
}
|
||||
|
||||
//go:linkname mapiternext github.com/goplus/llgo/internal/runtime.mapiternext
|
||||
func mapiternext(it *hiter)
|
||||
|
||||
//go:linkname mapclear github.com/goplus/llgo/internal/runtime.mapclear
|
||||
func mapclear(t *abi.Type, m unsafe.Pointer)
|
||||
|
||||
//go:linkname typehash github.com/goplus/llgo/internal/runtime.typehash
|
||||
func typehash(t *abi.Type, p unsafe.Pointer, h uintptr) uintptr
|
||||
|
||||
// MakeSlice creates a new zero-initialized slice value
|
||||
// for the specified slice type, length, and capacity.
|
||||
func MakeSlice(typ Type, len, cap int) Value {
|
||||
@@ -2632,6 +2661,22 @@ func MakeSlice(typ Type, len, cap int) Value {
|
||||
return Value{&typ.(*rtype).t, unsafe.Pointer(&s), flagIndir | flag(Slice)}
|
||||
}
|
||||
|
||||
// MakeMap creates a new map with the specified type.
|
||||
func MakeMap(typ Type) Value {
|
||||
return MakeMapWithSize(typ, 0)
|
||||
}
|
||||
|
||||
// MakeMapWithSize creates a new map with the specified type
|
||||
// and initial space for approximately n elements.
|
||||
func MakeMapWithSize(typ Type, n int) Value {
|
||||
if typ.Kind() != Map {
|
||||
panic("reflect.MakeMapWithSize of non-map type")
|
||||
}
|
||||
t := typ.common()
|
||||
m := makemap(t, n)
|
||||
return Value{t, m, flag(Map)}
|
||||
}
|
||||
|
||||
func ifaceE2I(t *abi.Type, src any, dst unsafe.Pointer) {
|
||||
panic("todo: reflect.ifaceE2I")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user