llgo: check hasImethod#89
Conversation
There was a problem hiding this comment.
Code Review
This pull request refactors method creation and method set initialization in rtype_llgo.go and methodof.go by returning unsafe.Pointer directly from createMethod and avoiding repeated calls to UnsafePointer(). It also introduces conditional logic based on whether a method is an interface method (hasIfn). However, in methodof.go, replacing unsafe.Pointer(reflect.ValueOf(...).Pointer()) with reflect.ValueOf(...).UnsafePointer() directly will cause a compilation error because UnsafePointer() returns a uintptr instead of an unsafe.Pointer. This needs to be wrapped in an explicit cast.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
|
|
||
| var ( | ||
| zeroIfn = unsafe.Pointer(reflect.ValueOf(func() {}).Pointer()) | ||
| zeroIfn = reflect.ValueOf(func() {}).UnsafePointer() |
There was a problem hiding this comment.
In standard Go (which is used for the !llgo build in methodof.go), reflect.Value.UnsafePointer() returns a uintptr, not an unsafe.Pointer. Assigning it directly to zeroIfn without an explicit cast will cause a compilation error when zeroIfn is later used as an unsafe.Pointer (e.g., at line 272: var pifn unsafe.Pointer = zeroIfn).
To fix this while still using the non-deprecated UnsafePointer() method, wrap the call in unsafe.Pointer(...).
| zeroIfn = reflect.ValueOf(func() {}).UnsafePointer() | |
| zeroIfn = unsafe.Pointer(reflect.ValueOf(func() {}).UnsafePointer()) |
There was a problem hiding this comment.
Review Summary
The change is a clean, sound refactor of the llgo method-set path plus a small cleanup in the !llgo path. createMethod now returns unsafe.Pointer directly and gates interface-function trampoline creation on ctx.hasImethod(...), substituting a shared zeroIfn when a method has no interface function — a genuine allocation saving for non-interface methods. The zeroIfn switch from unsafe.Pointer(reflect.ValueOf(...).Pointer()) to .UnsafePointer() is the correct, go vet-safe idiom. go build ./... (default !llgo tag) passes and both files are gofmt-clean.
No blocking issues. A few lower-confidence notes for your consideration:
-
onePtrgating divergence (confirm intent). In the!llgoreference (methodof.go:286), the value-methodifnis gated onhasIfn && onePtr, whereas the newllgopath gates only onhasIfn(rtype_llgo.go:372-380). This is very likely correct because the two backends use different interface ABIs — the!llgopath uses the Go runtime's direct-interface machinery (registerMethod/OnePtr), whilellgousestextOff/Ifn_slots and theDirectIfaceDatalinkname. Flagging only so you can confirm theonePtrconcept is intentionally absent here. -
Test coverage. This is the first change routing
hasImethodinto thellgocreateMethodpath and emittingzeroIfnfor the!hasIfncase, but there is no test exercising thehasIfn == falsebranch.llgo-tagged code generally can't run under the standardgo testtoolchain, which likely explains the gap — noting it as a coverage caveat, not a blocker. -
Docs.
SetHasImethod(context.go:33) — now load-bearing for this behavior — has no doc comment; a one-line note on what returningfalseimplies (interfaceIfnset tozeroIfn) would help callers.
See the inline comment for a robustness suggestion on the zeroIfn sentinel.
| } | ||
|
|
||
| var ( | ||
| zeroIfn = reflect.ValueOf(func() {}).UnsafePointer() |
There was a problem hiding this comment.
The empty-func sentinel zeroIfn is safe only under the invariant that methods with hasImethod == false are never dispatched through an itab. If a caller-supplied SetHasImethod callback ever wrongly returns false for a method that is used via an interface, the runtime would jump into an empty func(){} with a mismatched calling convention — producing silent wrong return values / potential frame corruption rather than a fail-fast crash.
Consider a panicking sentinel to make invariant violations diagnosable:
zeroIfn = reflect.ValueOf(func() { panic("reflectx: ifn called for method without imethod") }).UnsafePointer()Hardening suggestion, not a bug in the diff (default hasImethod returns true, preserving prior behavior when no callback is installed).
No description provided.