From 10fc169707491469458185bdca55d53c97a66e7b Mon Sep 17 00:00:00 2001 From: Richard Elkins Date: Sat, 11 Apr 2026 14:07:24 -0500 Subject: [PATCH] Junie-generated fixParamSlots and verifyParamsSlots --- src/fixParamSlots/main.go | 72 +++++++++++++++++++++++++++++ src/verifyParamSlots/main.go | 90 ++++++++++++++++++++++++++++++++++++ 2 files changed, 162 insertions(+) create mode 100644 src/fixParamSlots/main.go create mode 100644 src/verifyParamSlots/main.go diff --git a/src/fixParamSlots/main.go b/src/fixParamSlots/main.go new file mode 100644 index 0000000..a9b27f5 --- /dev/null +++ b/src/fixParamSlots/main.go @@ -0,0 +1,72 @@ +package main + +import ( + "fmt" + "os" + "os/exec" + "strings" +) + +func main() { + // 1. Run the verification script to get the mismatches. + // We expect verify_paramslots.go to be present in the root. + cmd := exec.Command("go", "run", "verify_paramslots.go") + output, err := cmd.CombinedOutput() + if err != nil { + fmt.Printf("Error running verification: %v\nOutput: %s\n", err, string(output)) + return + } + + lines := strings.Split(strings.TrimSpace(string(output)), "\n") + if len(lines) == 0 || (len(lines) == 1 && lines[0] == "") { + fmt.Println("No mismatches found.") + return + } + + for _, line := range lines { + parts := strings.Split(line, "|") + if len(parts) != 4 { + continue + } + path := parts[0] + sig := parts[1] + declaredSlots := parts[2] + expectedSlots := parts[3] + + fmt.Printf("Fixing %s in %s: %s -> %s\n", sig, path, declaredSlots, expectedSlots) + + content, err := os.ReadFile(path) + if err != nil { + fmt.Printf("Error reading %s: %v\n", path, err) + continue + } + + // Create the search and replace strings. + // We'll search for the specific signature assignment line to avoid errors. + searchStr := fmt.Sprintf(`ghelpers.MethodSignatures["%s"] = + ghelpers.GMeth{ParamSlots: %s,`, sig, declaredSlots) + + replaceStr := fmt.Sprintf(`ghelpers.MethodSignatures["%s"] = + ghelpers.GMeth{ParamSlots: %s,`, sig, expectedSlots) + + // Check if searchStr exists in the file. + newContent := strings.Replace(string(content), searchStr, replaceStr, 1) + + // If it's not found with that exact spacing/format, we'll try a simpler version. + if newContent == string(content) { + searchStr = fmt.Sprintf(`ghelpers.MethodSignatures["%s"] = ghelpers.GMeth{ParamSlots: %s,`, sig, declaredSlots) + replaceStr = fmt.Sprintf(`ghelpers.MethodSignatures["%s"] = ghelpers.GMeth{ParamSlots: %s,`, sig, expectedSlots) + newContent = strings.Replace(string(content), searchStr, replaceStr, 1) + } + + if newContent == string(content) { + fmt.Printf("Could not find signature assignment in %s for %s with slots %s\n", path, sig, declaredSlots) + continue + } + + err = os.WriteFile(path, []byte(newContent), 0644) + if err != nil { + fmt.Printf("Error writing to %s: %v\n", path, err) + } + } +} diff --git a/src/verifyParamSlots/main.go b/src/verifyParamSlots/main.go new file mode 100644 index 0000000..016baa4 --- /dev/null +++ b/src/verifyParamSlots/main.go @@ -0,0 +1,90 @@ +package main + +import ( + "fmt" + "io/fs" + "os" + "path/filepath" + "regexp" + "strings" +) + +// parseSignature parses a Java method descriptor and returns the number of parameter slots. +// According to the latest rule: 1 slot for long (J) and 1 slot for double (D). +func parseSignature(sig string) (int, error) { + idxStart := strings.Index(sig, "(") + idxEnd := strings.Index(sig, ")") + if idxStart == -1 || idxEnd == -1 || idxEnd < idxStart { + return 0, fmt.Errorf("invalid descriptor: %s", sig) + } + params := sig[idxStart+1 : idxEnd] + count := 0 + inRef := false + for i := 0; i < len(params); i++ { + if inRef { + if params[i] == ';' { + inRef = false + count++ + } + continue + } + switch params[i] { + case '[': + // Array type: skip '[' and process the base type as one slot. + continue + case 'L': + inRef = true + default: + // Primitives: B, C, D, F, I, J, S, Z + // Per instruction: J (long) and D (double) are 1 slot each. + count++ + } + } + return count, nil +} + +func main() { + // Matches ghelpers.MethodSignatures["..."] = ghelpers.GMeth{ParamSlots: X, ...} + // or ghelpers.MethodSignatures[types.ClassName...] = ghelpers.GMeth{ParamSlots: X, ...} + // We'll use a regex to find these assignments. + re := regexp.MustCompile(`ghelpers\.MethodSignatures\[(.*?)\]\s*=\s*(?:ghelpers\.)?GMeth\{\s*ParamSlots:\s*(\d+)`) + + err := filepath.WalkDir("src/gfunction", func(path string, d fs.DirEntry, err error) error { + if err != nil || d.IsDir() || !strings.HasSuffix(path, ".go") || strings.HasSuffix(path, "_test.go") { + return err + } + + content, err := os.ReadFile(path) + if err != nil { + return err + } + + matches := re.FindAllStringSubmatch(string(content), -1) + for _, m := range matches { + key := m[1] + declaredSlots := m[2] + + // The key might be a literal string or a constant. + // If it's a literal string like "java/lang/Object.()V", we can parse it. + if strings.HasPrefix(key, "\"") && strings.HasSuffix(key, "\"") { + sig := key[1 : len(key)-1] + expectedSlots, err := parseSignature(sig) + if err != nil { + continue + } + + if fmt.Sprintf("%d", expectedSlots) != declaredSlots { + fmt.Printf("%s|%s|%s|%d\n", path, sig, declaredSlots, expectedSlots) + } + } + // Handling constants like types.ClassNameBigDecimal + ".abs()Ljava/math/BigDecimal;" + // would require more complex parsing, but for the basic string literals, this works. + } + return nil + }) + + if err != nil { + fmt.Fprintf(os.Stderr, "Error walking files: %v\n", err) + os.Exit(1) + } +}