Merge pull request #886 from visualfc/reflect.map

reflect: implement map
This commit is contained in:
xushiwei
2024-11-27 14:12:56 +08:00
committed by GitHub
4 changed files with 1113 additions and 329 deletions

View File

@@ -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")
}
}
}

View File

@@ -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")

View File

@@ -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)
// }
// }
// }
}

View File

@@ -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(&regArgs.Ptrs[st.ireg]))
// fallthrough
// case abiStepIntReg:
// storeRcvr(rcvr, unsafe.Pointer(&regArgs.Ints[st.ireg]))
// case abiStepFloatReg:
// storeRcvr(rcvr, unsafe.Pointer(&regArgs.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(&regArgs, 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(&regArgs, 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), &regArgs)
// 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(&regArgs, 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(&regArgs, 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")
}