Skip to content

Commit 5437642

Browse files
Update to reflect and reflectlite
1 parent cd055c9 commit 5437642

File tree

3 files changed

+104
-22
lines changed

3 files changed

+104
-22
lines changed

compiler/natives/src/internal/reflectlite/all_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,27 @@ func TestTypes(t *testing.T) {
2121
func TestNameBytesAreAligned(t *testing.T) {
2222
t.Skip("TestNameBytesAreAligned")
2323
}
24+
25+
// `A` is used with `B[T any]` and is otherwise not needed.
26+
//
27+
//gopherjs:purge for go1.19 without generics
28+
type (
29+
A struct{}
30+
B[T any] struct{}
31+
)
32+
33+
// removing the name tests using `B[T any]` for go1.19 without generics
34+
var nameTests = []nameTest{
35+
{(*int32)(nil), "int32"},
36+
{(*D1)(nil), "D1"},
37+
{(*[]D1)(nil), ""},
38+
{(*chan D1)(nil), ""},
39+
{(*func() D1)(nil), ""},
40+
{(*<-chan D1)(nil), ""},
41+
{(*chan<- D1)(nil), ""},
42+
{(*any)(nil), ""},
43+
{(*interface {
44+
F()
45+
})(nil), ""},
46+
{(*TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678)(nil), "TheNameOfThisTypeIsExactly255BytesLongSoWhenTheCompilerPrependsTheReflectTestPackageNameAndExtraStarTheLinkerRuntimeAndReflectPackagesWillHaveToCorrectlyDecodeTheSecondLengthByte0123456789_0123456789_0123456789_0123456789_0123456789_012345678"},
47+
}

compiler/natives/src/reflect/reflect.go

Lines changed: 71 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,6 +1179,11 @@ func (v Value) Cap() int {
11791179
return v.typ.Len()
11801180
case Chan, Slice:
11811181
return v.object().Get("$capacity").Int()
1182+
case Ptr:
1183+
if v.typ.Elem().Kind() == Array {
1184+
return v.typ.Elem().Len()
1185+
}
1186+
panic("reflect: call of reflect.Value.Cap on ptr to non-array Value")
11821187
}
11831188
panic(&ValueError{"reflect.Value.Cap", k})
11841189
}
@@ -1405,6 +1410,11 @@ func (v Value) Len() int {
14051410
return v.object().Get("$buffer").Get("length").Int()
14061411
case Map:
14071412
return v.object().Get("size").Int()
1413+
case Ptr:
1414+
if v.typ.Elem().Kind() == Array {
1415+
return v.typ.Elem().Len()
1416+
}
1417+
panic("reflect: call of reflect.Value.Len on ptr to non-array Value")
14081418
default:
14091419
panic(&ValueError{"reflect.Value.Len", k})
14101420
}
@@ -1450,6 +1460,29 @@ func (v Value) Set(x Value) {
14501460
v.ptr = x.ptr
14511461
}
14521462

1463+
func (v Value) bytesSlow() []byte {
1464+
switch v.kind() {
1465+
case Slice:
1466+
if v.typ.Elem().Kind() != Uint8 {
1467+
panic("reflect.Value.Bytes of non-byte slice")
1468+
}
1469+
return *(*[]byte)(v.ptr)
1470+
case Array:
1471+
if v.typ.Elem().Kind() != Uint8 {
1472+
panic("reflect.Value.Bytes of non-byte array")
1473+
}
1474+
if !v.CanAddr() {
1475+
panic("reflect.Value.Bytes of unaddressable byte array")
1476+
}
1477+
// Replace the following with JS to avoid using unsafe pointers.
1478+
// p := (*byte)(v.ptr)
1479+
// n := int((*arrayType)(unsafe.Pointer(v.typ)).len)
1480+
// return unsafe.Slice(p, n)
1481+
return js.InternalObject(v.ptr).Interface().([]byte)
1482+
}
1483+
panic(&ValueError{"reflect.Value.Bytes", v.kind()})
1484+
}
1485+
14531486
func (v Value) SetBytes(x []byte) {
14541487
v.mustBeAssignable()
14551488
v.mustBe(Slice)
@@ -1728,29 +1761,47 @@ func deepValueEqualJs(v1, v2 Value, visited [][2]unsafe.Pointer) bool {
17281761
return js.Global.Call("$interfaceIsEqual", js.InternalObject(valueInterface(v1, false)), js.InternalObject(valueInterface(v2, false))).Bool()
17291762
}
17301763

1731-
func methodNameSkip() string {
1732-
pc, _, _, _ := runtime.Caller(3)
1733-
f := runtime.FuncForPC(pc)
1734-
if f == nil {
1735-
return "unknown method"
1736-
}
1737-
// Function name extracted from the call stack can be different from vanilla
1738-
// Go. Here we try to fix stuff like "Object.$packages.reflect.Q.ptr.SetIterKey"
1739-
// into "Value.SetIterKey".
1740-
// This workaround may become obsolete after https://github.com/gopherjs/gopherjs/issues/1085
1741-
// is resolved.
1742-
name := f.Name()
1743-
idx := len(name) - 1
1744-
for idx > 0 {
1745-
if name[idx] == '.' {
1746-
break
1764+
func stringsLastIndex(s string, c byte) int {
1765+
for i := len(s) - 1; i >= 0; i-- {
1766+
if s[i] == c {
1767+
return i
17471768
}
1748-
idx--
17491769
}
1750-
if idx < 0 {
1751-
return name
1770+
return -1
1771+
}
1772+
1773+
func stringsHasPrefix(s, prefix string) bool {
1774+
return len(s) >= len(prefix) && s[:len(prefix)] == prefix
1775+
}
1776+
1777+
func valueMethodName() string {
1778+
var pc [5]uintptr
1779+
n := runtime.Callers(1, pc[:])
1780+
frames := runtime.CallersFrames(pc[:n])
1781+
var frame runtime.Frame
1782+
for more := true; more; {
1783+
frame, more = frames.Next()
1784+
name := frame.Function
1785+
1786+
// Function name extracted from the call stack can be different from
1787+
// vanilla Go, so is not prefixed by "reflect.Value." as needed by the original.
1788+
// See https://cs.opensource.google/go/go/+/refs/tags/go1.19.13:src/reflect/value.go;l=173-191
1789+
// Here we try to fix stuff like "Object.$packages.reflect.Q.ptr.SetIterKey"
1790+
// into "reflect.Value.SetIterKey".
1791+
// This workaround may become obsolete after
1792+
// https://github.com/gopherjs/gopherjs/issues/1085 is resolved.
1793+
1794+
const prefix = `Object.$packages.reflect.`
1795+
if stringsHasPrefix(name, prefix) {
1796+
if idx := stringsLastIndex(name, '.'); idx >= 0 {
1797+
methodName := name[idx+1:]
1798+
if len(methodName) > 0 && 'A' <= methodName[0] && methodName[0] <= 'Z' {
1799+
return `reflect.Value.` + methodName
1800+
}
1801+
}
1802+
}
17521803
}
1753-
return "Value" + name[idx:]
1804+
return "unknown method"
17541805
}
17551806

17561807
func verifyNotInHeapPtr(p uintptr) bool {

compiler/natives/src/reflect/reflect_test.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -285,9 +285,16 @@ func TestMethodCallValueCodePtr(t *testing.T) {
285285
t.Skip("methodValueCallCodePtr() is not applicable in GopherJS")
286286
}
287287

288-
type B struct{}
288+
//gopherjs:purge for go1.19 without generics
289+
type (
290+
A struct{}
291+
B[T any] struct{}
292+
)
289293

290-
//gopherjs:prune-original
291294
func TestIssue50208(t *testing.T) {
292295
t.Skip("This test required generics, which are not yet supported: https://github.com/gopherjs/gopherjs/issues/1013")
293296
}
297+
298+
func TestStructOfTooLarge(t *testing.T) {
299+
t.Skip("This test is dependent on field alignment to determine if a struct size would exceed virtual address space.")
300+
}

0 commit comments

Comments
 (0)