Files
five/hbrt/gobridge_fast.go
Charles KWON OhJun 59568f3301 Five v0.9 — Harbour + Go fusion language
- Compiler: PP → Lexer → Parser → Analyzer → Gengo pipeline
- Parser: 232/236 (98%) Harbour compatibility, registry-based dispatch
- RTL: 351 Harbour-compatible functions
- RDD: DBF/NTX/CDX engines with Rushmore bitmap optimization
- Go Interop: IMPORT + pkg.Func() + obj:Method() with FastPath (15M calls/sec)
- HB_FUNC API: Full Harbour C API compatible Go bridge
- Concurrency: SPAWN/LAUNCH/GOROUTINE, <-, WATCH, PARALLEL FOR, ASYNC/AWAIT
- Extensions: Multi-return, DEFER, Slice, f-string, Nil-safe ?:, CONST
- Macro Compiler: Runtime AST parsing and evaluation
- Debugger: TUI debugger with source display, breakpoints, stepping
- FRB: Native + Pcode dual mode runtime binary
- Tests: 13 packages ALL PASS

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 09:41:50 +09:00

207 lines
5.8 KiB
Go

// Copyright (c) 2026 Charles KWON OhJun (charleskwonohjun@gmail.com)
// All rights reserved.
// gobridge_fast.go — Performance optimizations for Go interop.
//
// Strategy 1: Method cache — cache reflect.Method by (type, name)
// Strategy 2: Fast path — bypass reflect for common signatures
// Strategy 3: Function registry — pre-register Go funcs with typed wrappers
package hbrt
import (
"reflect"
"sync"
)
// ---------------------------------------------------------------------------
// 1. Method Cache — cache reflect.Method by (type, methodName)
// ---------------------------------------------------------------------------
type methodKey struct {
typ reflect.Type
name string
}
var (
methodCache = make(map[methodKey]reflect.Method)
methodCacheMu sync.RWMutex
)
// cachedMethod looks up a method with caching.
func cachedMethod(rv reflect.Value, name string) (reflect.Value, bool) {
key := methodKey{rv.Type(), name}
methodCacheMu.RLock()
m, ok := methodCache[key]
methodCacheMu.RUnlock()
if ok {
return rv.Method(m.Index), true
}
// Slow path: lookup and cache
mt, found := rv.Type().MethodByName(name)
if !found {
return reflect.Value{}, false
}
methodCacheMu.Lock()
methodCache[key] = mt
methodCacheMu.Unlock()
return rv.Method(mt.Index), true
}
// ---------------------------------------------------------------------------
// 2. Fast Path — common function signatures without reflect
// ---------------------------------------------------------------------------
// FastFunc is a type-specialized Go function wrapper.
// Avoids reflect.Call for common signatures.
type FastFunc struct {
name string
fn interface{} // original function for fallback
// Typed fast paths (only one is non-nil)
fnSS func(string) string // string → string
fnSSB func(string, string) bool // string, string → bool
fnSSS func(string, string) string // string, string → string
fnSSSS func(string, string, string) string // string, string, string → string
fnSI func(string) int // string → int
fnSSI func(string, string) int // string, string → int
fnFI func(float64) float64 // float64 → float64
fnFFI func(float64, float64) float64 // float64, float64 → float64
fnII func(int) int // int → int
}
// GoCallFast calls a pre-registered fast function.
func GoCallFast(ff *FastFunc, args ...Value) []Value {
n := len(args)
// Try fast paths first
if ff.fnSS != nil && n == 1 {
return []Value{MakeString(ff.fnSS(args[0].AsString()))}
}
if ff.fnSSB != nil && n == 2 {
return []Value{MakeBool(ff.fnSSB(args[0].AsString(), args[1].AsString()))}
}
if ff.fnSSS != nil && n == 2 {
return []Value{MakeString(ff.fnSSS(args[0].AsString(), args[1].AsString()))}
}
if ff.fnSSSS != nil && n == 3 {
return []Value{MakeString(ff.fnSSSS(args[0].AsString(), args[1].AsString(), args[2].AsString()))}
}
if ff.fnSI != nil && n == 1 {
return []Value{MakeInt(ff.fnSI(args[0].AsString()))}
}
if ff.fnSSI != nil && n == 2 {
return []Value{MakeInt(ff.fnSSI(args[0].AsString(), args[1].AsString()))}
}
if ff.fnFI != nil && n == 1 {
return []Value{MakeDouble(ff.fnFI(args[0].AsNumDouble()), 0, 0)}
}
if ff.fnFFI != nil && n == 2 {
return []Value{MakeDouble(ff.fnFFI(args[0].AsNumDouble(), args[1].AsNumDouble()), 0, 0)}
}
if ff.fnII != nil && n == 1 {
return []Value{MakeInt(ff.fnII(args[0].AsInt()))}
}
// Fallback to reflect
return GoCallFunc(ff.fn, args...)
}
// ---------------------------------------------------------------------------
// 3. GoCallCached — GoCall with method cache
// ---------------------------------------------------------------------------
// GoCallCached is a faster version of GoCall that caches method lookups.
func GoCallCached(receiver Value, method string, args ...Value) []Value {
obj := UnwrapGo(receiver)
if obj == nil {
return []Value{MakeNil(), MakeString("nil receiver")}
}
rv := reflect.ValueOf(obj)
m, ok := cachedMethod(rv, method)
if !ok {
return []Value{MakeNil(), MakeString("method not found: " + method)}
}
mt := m.Type()
isVariadic := mt.IsVariadic()
fixedCount := mt.NumIn()
if isVariadic {
fixedCount--
}
goArgs := make([]reflect.Value, len(args))
for i, arg := range args {
if i < fixedCount {
goArgs[i] = valueToReflect(arg, mt.In(i))
} else if isVariadic {
elemType := mt.In(mt.NumIn() - 1).Elem()
goArgs[i] = valueToReflect(arg, elemType)
} else {
goArgs[i] = reflect.ValueOf(valueToInterface(arg))
}
}
results := m.Call(goArgs)
hbResults := make([]Value, len(results))
for i, r := range results {
hbResults[i] = reflectToValue(r)
}
return hbResults
}
// ---------------------------------------------------------------------------
// 4. Function Registry — pre-register known functions
// ---------------------------------------------------------------------------
var (
fastFuncRegistry = make(map[string]*FastFunc)
fastFuncRegistryMu sync.RWMutex
)
// RegisterFastFunc registers a Go function with typed fast paths.
func RegisterFastFunc(name string, fn interface{}) *FastFunc {
ff := &FastFunc{name: name, fn: fn}
// Auto-detect signature and set fast path
switch f := fn.(type) {
case func(string) string:
ff.fnSS = f
case func(string, string) bool:
ff.fnSSB = f
case func(string, string) string:
ff.fnSSS = f
case func(string, string, string) string:
ff.fnSSSS = f
case func(string) int:
ff.fnSI = f
case func(string, string) int:
ff.fnSSI = f
case func(float64) float64:
ff.fnFI = f
case func(float64, float64) float64:
ff.fnFFI = f
case func(int) int:
ff.fnII = f
}
fastFuncRegistryMu.Lock()
fastFuncRegistry[name] = ff
fastFuncRegistryMu.Unlock()
return ff
}
// GetFastFunc looks up a registered fast function.
func GetFastFunc(name string) *FastFunc {
fastFuncRegistryMu.RLock()
ff := fastFuncRegistry[name]
fastFuncRegistryMu.RUnlock()
return ff
}