1
0
mirror of https://github.com/golang/go synced 2024-11-19 09:24:39 -07:00
Commit Graph

6 Commits

Author SHA1 Message Date
Alan Donovan
aff951c80f go.tools/pointer: more reflection operators.
(reflect.Value).Bytes
(reflect.Value).Elem
(reflect.Value).Index
(reflect.Value).SetBytes
(reflect.Value).Slice
reflect.PtrTo
reflect.SliceOf

+ Tests.

Also: comment out an 'info-'level print statement in the test; it was distracting.

R=crawshaw
CC=golang-dev
https://golang.org/cl/14454055
2013-10-11 15:34:19 -04:00
Alan Donovan
5b55a71008 go.tools/pointer: strength reduction during constraint generation.
Motivation: simple constraints---copy and addr---are more
amenable to pre-solver optimizations (forthcoming) than
complex constraints: load, store, and all others.

In code such as the following:

         t0 = new struct { x, y int }
         t1 = &t0.y
         t2 = *t1

there's no need for the full generality of a (complex)
load constraint for t2=*t1 since t1 can only point to t0.y.
All we need is a (simple) copy constraint t2 = (t0.y)
where (t0.y) is the object node label for that field.

For all "addressable" SSA instructions, we tabulate
whether their points-to set is necessarily a singleton.  For
some (e.g. Alloc, MakeSlice, etc) this is always true by
design.  For others (e.g. FieldAddr) it depends on their
operands.

We exploit this information when generating constraints:
all load-form and store-form constraints are reduced to copy
constraints if the pointer's PTS is a singleton.
Similarly all FieldAddr (y=&x.f) and IndexAddr (y=&x[0])
constraints are reduced to offset addition, for singleton
operands.

Here's the constraint mix when running on the oracle itself.
The total number of constraints is unchanged but the fraction
that are complex has gone down to 21% from 53%.

                before    after
--simple--
 addr		20682     46949
 copy        	61454     91211
--complex--
 offsetAddr  	41621     15325
 load        	18769     12925
 store       	30758     6908
 invoke      	758       760
 typeAssert  	1688      1689
total           175832    175869

Also:
- Add Pointer.Context() for local variables,
  since we now plumb cgnodes throughout. Nice.
- Refactor all load-form (load, receive, lookup) and
  store-form (Store, send, MapUpdate) constraints to use
  genLoad and genStore.
- Log counts of constraints by type.
- valNodes split into localval and globalval maps;
  localval is purged after each function.
- analogous maps localobj[v] and globalobj[v] hold sole label
  for pts(v), if singleton.
- fnObj map subsumed by globalobj.
- make{Function/Global/Constant} inlined into objectValue.
  Much cleaner.

R=crawshaw
CC=golang-dev
https://golang.org/cl/13979043
2013-09-27 11:33:01 -04:00
Alan Donovan
3371b79a96 go.tools/pointer: reflect, part 2: channels.
(reflect.Value).Send
        (reflect.Value).TrySend
        (reflect.Value).Recv
        (reflect.Value).TryRecv
        (reflect.Type).ChanOf
        (reflect.Type).In
        (reflect.Type).Out
        reflect.Indirect
        reflect.MakeChan

Also:
- specialize genInvoke when the receiver is a reflect.Type under the
  assumption that there's only one possible concrete type.  This
  makes all reflect.Type operations context-sensitive since the calls
  are no longer dynamic.
- Rename all variables to match the actual parameter names used in
  the reflect API.
- Add pointer.Config.Reflection flag
  (exposed in oracle as --reflect, default false) to enable reflection.
  It currently adds about 20% running time.  I'll make it true after
  the presolver is implemented.
- Simplified worklist datatype and solver main loop slightly
  (~10% speed improvement).
- Use addLabel() utility to add a label to a PTS.

(Working on my 3 yr old 2x2GHz+4GB Mac vs 8x4GHz+24GB workstation,
one really notices the cost of pointer analysis.
Note to self: time to implement presolver.)

R=crawshaw
CC=golang-dev
https://golang.org/cl/13242062
2013-09-23 16:13:01 -04:00
Alan Donovan
3b5de067a1 go.tools/pointer: reflection, part 1: maps, and some core features.
Core:
        reflect.TypeOf
        reflect.ValueOf
        reflect.Zero
        reflect.Value.Interface
Maps:
        (reflect.Value).MapIndex
        (reflect.Value).MapKeys
        (reflect.Value).SetMapIndex
        (*reflect.rtype).Elem
        (*reflect.rtype).Key

+ tests:
  pointer/testdata/mapreflect.go.
  oracle/testdata/src/main/reflection.go.

Interface objects (T, V...) have been renamed "tagged objects".

Abstraction: we model reflect.Value similar to
interface{}---as a pointer that points only to tagged
objects---but a reflect.Value may also point to an "indirect
tagged object", one in which the payload V is of type *T not T.
These are required because reflect.Values can hold lvalues,
e.g. when derived via Field() or Elem(), though we won't use
them till we get to structs and pointers.

Solving: each reflection intrinsic defines a new constraint
and resolution rule.  Because of the nature of reflection,
generalizing across types, the resolution rules dynamically
create additional complex constraints during solving, where
previously only simple (copy) constraints were created.
This requires some solver changes:

  The work done before the main solver loop (to attach new
  constraints to the graph) is now done before each iteration,
  in processNewConstraints.

  Its loop over constraints is broken into two passes:
  the first handles base (addr-of) constraints,
  the second handles simple and complex constraints.

  constraint.init() has been inlined.  The only behaviour that
  varies across constraints is ptr()

Sadly this will pessimize presolver optimisations, when we get
there; such is the price of reflection.

Objects: reflection intrinsics create objects (i.e. cause
memory allocations) with no SSA operation.  We will represent
them as the cgnode of the instrinsic (e.g. reflect.New), so we
extend Labels and node.data to represent objects as a product
(not sum) of ssa.Value and cgnode and pull this out into its
own type, struct object.  This simplifies a number of
invariants and saves space.  The ntObject flag is now
represented by obj!=nil; the other flags are moved into
object.

cgnodes are now always recorded in objects/Labels for which it
is appropriate (all but those for globals, constants and the
shared contours for functions).

Also:
- Prepopulate the flattenMemo cache to consider reflect.Value
  a fake pointer, not a struct.
- Improve accessors and documentation on type Label.
- @conctypes assertions renamed @types (since dyn. types needn't be concrete).
- add oracle 'describe' test on an interface (missing, an oversight).

R=crawshaw
CC=golang-dev
https://golang.org/cl/13418048
2013-09-16 09:49:10 -04:00
Alan Donovan
713699d8ad go.tools: add copyright messages to source files.
R=r
CC=golang-dev
https://golang.org/cl/13305043
2013-08-27 18:49:13 -04:00
Alan Donovan
6643abb26c go.tools/pointer: inclusion-based pointer analysis for Go.
Suggested reading order:
- doc.go
- api.go, analysis.go, callgraph.go, labels.go
- print.go, util.go
- gen.go
- solve.go
- pointer_test.go, testdata/*
- intrinsics.go (none are implemented yet)

R=dannyb, gri, crawshaw, 0xjnml
CC=golang-dev
https://golang.org/cl/10618043
2013-08-22 12:27:55 -04:00