| package builder |
| |
| import ( |
| "fmt" |
| "reflect" |
| |
| "android.googlesource.com/platform/tools/gpu/atom" |
| "android.googlesource.com/platform/tools/gpu/binary" |
| "android.googlesource.com/platform/tools/gpu/database" |
| "android.googlesource.com/platform/tools/gpu/gfxapi" |
| "android.googlesource.com/platform/tools/gpu/log" |
| "android.googlesource.com/platform/tools/gpu/memory" |
| "android.googlesource.com/platform/tools/gpu/service" |
| "android.googlesource.com/platform/tools/gpu/service/path" |
| ) |
| |
| // Resolve resolves and returns the object, value or memory at the path p. |
| func Resolve(p path.Path, d database.Database, l log.Logger) (interface{}, error) { |
| v, err := resolveChain(path.Flatten(p), d, l) |
| if err != nil { |
| return nil, err |
| } |
| return v[len(v)-1], nil |
| } |
| |
| // ResolveCapture resolves and returns the capture from the path p. |
| func ResolveCapture(p *path.Capture, d database.Database, l log.Logger) (service.Capture, error) { |
| if res, err := Resolve(p, d, l); err == nil { |
| return *res.(*service.Capture), nil |
| } else { |
| return service.Capture{}, err |
| } |
| } |
| |
| // ResolveAtoms resolves and returns the atom list from the path p. |
| func ResolveAtoms(p *path.Atoms, d database.Database, l log.Logger) ([]atom.Atom, error) { |
| if res, err := Resolve(p, d, l); err == nil { |
| return res.(*atom.List).Atoms, nil |
| } else { |
| return nil, err |
| } |
| } |
| |
| // ResolveAtom resolves and returns the atom from the path p. |
| func ResolveAtom(p *path.Atom, d database.Database, l log.Logger) (atom.Atom, error) { |
| if res, err := Resolve(p, d, l); err == nil { |
| return res.(atom.Atom), nil |
| } else { |
| return nil, err |
| } |
| } |
| |
| func resolveChain(paths []path.Path, d database.Database, l log.Logger) ([]interface{}, error) { |
| v := make([]interface{}, len(paths)) |
| for i, p := range paths { |
| switch p := p.(type) { |
| case *path.Capture: |
| capture, err := service.ResolveCapture(p.ID, d, l) |
| if err != nil { |
| return nil, err |
| } |
| v[i] = capture |
| |
| case *path.Device: |
| device, err := service.ResolveDevice(p.ID, d, l) |
| if err != nil { |
| return nil, err |
| } |
| v[i] = device |
| |
| case *path.ImageInfo: |
| r, err := service.ResolveImageInfo(p.ID, d, l) |
| if err != nil { |
| return nil, err |
| } |
| v[i] = r |
| |
| case *path.TimingInfo: |
| r, err := service.ResolveTimingInfo(p.ID, d, l) |
| if err != nil { |
| return nil, err |
| } |
| v[i] = r |
| |
| case *path.Blob: |
| if blob, err := database.Resolve(p.ID, d, l); err != nil { |
| return nil, err |
| } else if data, ok := blob.([]byte); !ok { |
| return nil, fmt.Errorf("ID %s gave %T, expected []byte", p.ID, blob) |
| } else { |
| v[i] = data |
| } |
| |
| case *path.Atoms: |
| capture := v[i-1].(*service.Capture) |
| atoms, err := database.Resolve(binary.ID(capture.Atoms), d, l) |
| if err != nil { |
| return nil, err |
| } |
| v[i] = atoms |
| |
| case *path.Report: |
| report, err := database.Build(&BuildReport{Capture: p.Capture}, d, l) |
| if err != nil { |
| return nil, err |
| } |
| v[i] = report.(*service.Report) |
| |
| case *path.Hierarchy: |
| root, err := database.Build(&GetHierarchy{Capture: p.Capture}, d, l) |
| if err != nil { |
| return nil, err |
| } |
| v[i] = root.(*atom.Group) |
| |
| case *path.Atom: |
| atoms := v[i-1].(*atom.List).Atoms |
| if p.Index >= uint64(len(atoms)) { |
| return nil, fmt.Errorf("Atom at %s is out of bounds [0-%d]", |
| p.Path(), len(atoms)-1) |
| } |
| v[i] = atoms[p.Index] |
| |
| case *path.State: |
| atoms := v[i-2].(*atom.List).Atoms |
| if p.After.Index >= uint64(len(atoms)) { |
| return nil, fmt.Errorf("%v is out of bounds. [0-%d]", p, len(atoms)-1) |
| } |
| api := gfxapi.Find(atoms[p.After.Index].API()) |
| if api == nil { |
| return nil, fmt.Errorf("Atom at %s has no API", |
| paths[i-1].Path()) |
| } |
| s := gfxapi.NewState() |
| for _, a := range atoms[:p.After.Index] { |
| a.Mutate(s, d, l) |
| } |
| res, found := s.APIs[api] |
| if !found { |
| return nil, fmt.Errorf("No state for API '%v' after %v", |
| api.Name(), paths[i-1].Path()) |
| } |
| v[i] = res |
| |
| case *path.MemoryRange: |
| atoms := v[i-2].(*atom.List).Atoms |
| if p.After.Index >= uint64(len(atoms)) { |
| return nil, fmt.Errorf("%v is out of bounds. [0-%d]", p, len(atoms)-1) |
| } |
| |
| res, err := ResolveMemoryRange( |
| atoms, |
| atom.ID(p.After.Index), |
| memory.PoolID(p.Pool), |
| memory.Range{Base: p.Address, Size: p.Size}, |
| d, l) |
| if err != nil { |
| return nil, err |
| } |
| v[i] = res |
| |
| case *path.Field: |
| s := reflect.ValueOf(v[i-1]) |
| deref: |
| for { |
| switch s.Kind() { |
| case reflect.Struct: |
| f := s.FieldByName(p.Name) |
| if !f.IsValid() { |
| return nil, fmt.Errorf("Struct of type %v at %s does not have field '%s'", |
| s.Type(), paths[i-1].Path(), p.Name) |
| } |
| v[i] = s.FieldByName(p.Name).Interface() |
| break deref |
| case reflect.Interface, reflect.Ptr: |
| if s.IsNil() { |
| return nil, fmt.Errorf("Pointer at %s is nil", paths[i-1].Path()) |
| } |
| s = s.Elem() |
| default: |
| return nil, fmt.Errorf("Type %v at %s is not a struct", |
| s.Type(), paths[i-1].Path()) |
| } |
| } |
| |
| case *path.ArrayIndex: |
| a := reflect.ValueOf(v[i-1]) |
| switch a.Kind() { |
| case reflect.Array, reflect.Slice, reflect.String: |
| if int(p.Index) >= a.Len() { |
| return nil, fmt.Errorf("Index at %s is out of bounds [0-%d]", p.Path(), a.Len()-1) |
| } |
| v[i] = a.Index(int(p.Index)).Interface() |
| |
| default: |
| return nil, fmt.Errorf("Type %v at %s is not an array, slice or string", |
| a.Type(), paths[i-1].Path()) |
| } |
| |
| case *path.Slice: |
| a := reflect.ValueOf(v[i-1]) |
| switch a.Kind() { |
| case reflect.Array, reflect.Slice, reflect.String: |
| if int(p.Start) >= a.Len() || int(p.End) > a.Len() { |
| return nil, fmt.Errorf("Slice at %s is out of bounds [0-%d]", p.Path(), a.Len()-1) |
| } |
| v[i] = a.Slice(int(p.Start), int(p.End)).Interface() |
| |
| default: |
| return nil, fmt.Errorf("Type %v at %s is not an array, slice or string", |
| a.Type(), paths[i-1].Path()) |
| } |
| |
| case *path.MapIndex: |
| m := reflect.ValueOf(v[i-1]) |
| switch m.Kind() { |
| case reflect.Map: |
| key, ok := convert(reflect.ValueOf(p.Key), m.Type().Key()) |
| if !ok { |
| return nil, fmt.Errorf("Map at %s has key of type %v, got type %v", |
| paths[i-1].Path(), m.Type().Key(), key.Type()) |
| } |
| val := m.MapIndex(key) |
| if !val.IsValid() { |
| return nil, fmt.Errorf("Map at %s does not contain key %v", |
| paths[i-1].Path(), p.Key) |
| } |
| v[i] = val.Interface() |
| |
| default: |
| return nil, fmt.Errorf("Type %v at %s is not a map", |
| m.Type(), paths[i-1].Path()) |
| } |
| |
| default: |
| return nil, fmt.Errorf("Unknown path type %T", p) |
| } |
| } |
| |
| return v, nil |
| } |
| |
| func convert(val reflect.Value, ty reflect.Type) (reflect.Value, bool) { |
| if valTy := val.Type(); valTy != ty { |
| if valTy.ConvertibleTo(ty) { |
| val = val.Convert(ty) |
| } else { |
| return val, false |
| } |
| } |
| return val, true |
| } |