-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Restore dead code elimination for callbacks by reverting to constant MethodByName lookups #7625
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Restore Re-introduces a specialized reflection helper that performs Key Changes• Added Affected Areas• This summary was automatically generated by @propel-code-bot |
…loses go-gorm#7622) Commit 725aa5b replaced the specialized callBackToMethodValue() function with MethodByName(string(cbName)) to fix data race issues, but this inadvertently broke dead code elimination optimization. The original function used explicit string constants in MethodByName calls, which allows the Go compiler/linker to perform dead code elimination. Using MethodByName with a variable parameter prevents this optimization, potentially increasing binary size for large projects. This restores the callBackToMethodValue function while preserving the data race fixes from commit 725aa5b, ensuring both thread safety and optimal binary size for enterprise customers building large binaries. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
3510750 to
ba1d4bd
Compare
Adds comprehensive tests to verify that the callBackToMethodValue function properly supports dead code elimination by using explicit string constants instead of the anti-pattern of MethodByName(string(variable)). The tests serve multiple purposes: 1. Functional verification - Ensure callback detection works correctly 2. Problem demonstration - Running with -dumpdep shows the issue 3. Before/after comparison - Proves the optimization works Evidence from go test -ldflags=-dumpdep: BROKEN VERSION (without fix): - ParseWithSpecialTableName <ReflectMethod> -> reflect.Value.MethodByName - Shows <ReflectMethod> tag indicating poor dead code elimination FIXED VERSION (with callBackToMethodValue): - ParseWithSpecialTableName -> gorm.io/gorm/schema.callBackToMethodValue - NO <ReflectMethod> tag, proving dead code elimination is working The <ReflectMethod> tag elimination confirms that explicit string constants allow the Go compiler and linker to perform proper dead code elimination, while the anti-pattern MethodByName(string(variable)) breaks this optimization. Tests verify: - Callback detection works correctly with explicit string constants - Functionality is preserved compared to models without callbacks - The fix maintains backward compatibility - Regression protection against future anti-pattern reintroduction - Build-time optimization verification via dumpdep analysis While this fix is implementation-dependent, it's a necessary workaround for the fundamental incompatibility between reflection and dead code elimination. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
Co-authored-by: propel-code-bot[bot] <203372662+propel-code-bot[bot]@users.noreply.github.com>
| func getLifecycleCallbackMethod(modelType reflect.Value, cbType callbackType) reflect.Value { | ||
| switch cbType { | ||
| case callbackTypeBeforeSave: | ||
| return modelType.MethodByName("BeforeSave") | ||
| case callbackTypeAfterSave: | ||
| return modelType.MethodByName("AfterSave") | ||
| case callbackTypeAfterFind: | ||
| return modelType.MethodByName("AfterFind") | ||
| default: | ||
| default: | ||
| return reflect.Value{} | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[CriticalError]
Duplicate default case in switch statement. This will cause a compilation error:
case callbackTypeAfterFind:
return modelType.MethodByName("AfterFind")
default:
default: // <-- Duplicate default case
return reflect.Value{}Suggested Change
| func getLifecycleCallbackMethod(modelType reflect.Value, cbType callbackType) reflect.Value { | |
| switch cbType { | |
| case callbackTypeBeforeSave: | |
| return modelType.MethodByName("BeforeSave") | |
| case callbackTypeAfterSave: | |
| return modelType.MethodByName("AfterSave") | |
| case callbackTypeAfterFind: | |
| return modelType.MethodByName("AfterFind") | |
| default: | |
| default: | |
| return reflect.Value{} | |
| } | |
| func getLifecycleCallbackMethod(modelType reflect.Value, cbType callbackType) reflect.Value { | |
| switch cbType { | |
| case callbackTypeBeforeSave: | |
| return modelType.MethodByName("BeforeSave") | |
| case callbackTypeAfterSave: | |
| return modelType.MethodByName("AfterSave") | |
| case callbackTypeAfterFind: | |
| return modelType.MethodByName("AfterFind") | |
| default: | |
| return reflect.Value{} | |
| } | |
| } |
⚡ Committable suggestion
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.
Context for Agents
[**CriticalError**]
Duplicate `default` case in switch statement. This will cause a compilation error:
```go
case callbackTypeAfterFind:
return modelType.MethodByName("AfterFind")
default:
default: // <-- Duplicate default case
return reflect.Value{}
```
<details>
<summary>Suggested Change</summary>
```suggestion
func getLifecycleCallbackMethod(modelType reflect.Value, cbType callbackType) reflect.Value {
switch cbType {
case callbackTypeBeforeSave:
return modelType.MethodByName("BeforeSave")
case callbackTypeAfterSave:
return modelType.MethodByName("AfterSave")
case callbackTypeAfterFind:
return modelType.MethodByName("AfterFind")
default:
return reflect.Value{}
}
}
```
⚡ **Committable suggestion**
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.
</details>
File: schema/schema.go
Line: 436|
closing this pr due to build failed. |
|
Resubmitted in #7643 |
Summary
callBackToMethodValuefunction that was removed in commit 725aa5bProblem
Commit 725aa5b replaced the specialized
callBackToMethodValue()function withMethodByName(string(cbName))to fix data race issues, but this inadvertently broke dead code elimination optimization.The original function used explicit string constants in
MethodByNamecalls, which allows the Go compiler/linker to perform dead code elimination. UsingMethodByNamewith a variable parameter prevents this optimization, potentially increasing binary size significantly for large projects.Solution
callBackToMethodValuefunction with explicit string constantsmodelValue.MethodByName(string(cbName))withcallBackToMethodValue(modelValue, cbName)Impact
Test plan
🤖 Generated with Claude Code