@@ -28,6 +28,21 @@ package ssa
28
28
// mutated during the CREATE phase, but during the BUILD phase they
29
29
// remain constant. The sole exception is Prog.methodSets and its
30
30
// related maps, which are protected by a dedicated mutex.
31
+ //
32
+ // Happens-before:
33
+ //
34
+ // The happens-before constraints (with X<Y denoting X happens-before Y) are:
35
+ // - CREATE fn < fn.startBody() < fn.finishBody() < fn.built
36
+ // for any function fn.
37
+ // - anon.parent.startBody() < CREATE anon, and
38
+ // anon.finishBody() < anon.parent().finishBody() < anon.built < fn.built
39
+ // for an anonymous function anon (i.e. anon.parent() != nil).
40
+ // - CREATE fn.Pkg < CREATE fn
41
+ // for a declared function fn (i.e. fn.Pkg != nil)
42
+ // - fn.built < BUILD pkg done
43
+ // for any function fn created during the CREATE or BUILD phase of a package
44
+ // pkg. This includes declared and synthetic functions.
45
+ //
31
46
32
47
import (
33
48
"fmt"
68
83
69
84
// builder holds state associated with the package currently being built.
70
85
// Its methods contain all the logic for AST-to-SSA conversion.
71
- type builder struct {}
86
+ type builder struct {
87
+ // Invariant: 0 <= rtypes <= finished <= created.Len()
88
+ created * creator // functions created during building
89
+ finished int // Invariant: create[i].built holds for i in [0,finished)
90
+ rtypes int // Invariant: all of the runtime types for create[i] have been added for i in [0,rtypes)
91
+ }
72
92
73
93
// cond emits to fn code to evaluate boolean condition e and jump
74
94
// to t or f depending on its value, performing various simplifications.
@@ -558,7 +578,10 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value {
558
578
info : fn .info ,
559
579
}
560
580
fn .AnonFuncs = append (fn .AnonFuncs , fn2 )
561
- b .buildFunction (fn2 )
581
+ b .created .Add (fn2 )
582
+ b .buildFunctionBody (fn2 )
583
+ // fn2 is not done BUILDing. fn2.referrers can still be updated.
584
+ // fn2 is done BUILDing after fn.finishBody().
562
585
if fn2 .FreeVars == nil {
563
586
return fn2
564
587
}
@@ -713,7 +736,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value {
713
736
case types .MethodExpr :
714
737
// (*T).f or T.f, the method f from the method-set of type T.
715
738
// The result is a "thunk".
716
- return emitConv (fn , makeThunk (fn .Prog , sel ), tv .Type )
739
+ return emitConv (fn , makeThunk (fn .Prog , sel , b . created ), tv .Type )
717
740
718
741
case types .MethodVal :
719
742
// e.f where e is an expression and f is a method.
@@ -730,7 +753,7 @@ func (b *builder) expr0(fn *Function, e ast.Expr, tv types.TypeAndValue) Value {
730
753
emitTypeAssert (fn , v , rt , token .NoPos )
731
754
}
732
755
c := & MakeClosure {
733
- Fn : makeBound (fn .Prog , obj ),
756
+ Fn : makeBound (fn .Prog , obj , b . created ),
734
757
Bindings : []Value {v },
735
758
}
736
759
c .setPos (e .Sel .Pos ())
@@ -2170,10 +2193,21 @@ start:
2170
2193
2171
2194
// buildFunction builds SSA code for the body of function fn. Idempotent.
2172
2195
func (b * builder ) buildFunction (fn * Function ) {
2196
+ if ! fn .built {
2197
+ assert (fn .parent == nil , "anonymous functions should not be built by buildFunction()" )
2198
+ b .buildFunctionBody (fn )
2199
+ fn .done ()
2200
+ }
2201
+ }
2202
+
2203
+ // buildFunctionBody builds SSA code for the body of function fn.
2204
+ //
2205
+ // fn is not done building until fn.done() is called.
2206
+ func (b * builder ) buildFunctionBody (fn * Function ) {
2207
+ // TODO(taking): see if this check is reachable.
2173
2208
if fn .Blocks != nil {
2174
2209
return // building already started
2175
2210
}
2176
-
2177
2211
var recvField * ast.FieldList
2178
2212
var body * ast.BlockStmt
2179
2213
var functype * ast.FuncType
@@ -2231,22 +2265,47 @@ func (b *builder) buildFunction(fn *Function) {
2231
2265
fn .finishBody ()
2232
2266
}
2233
2267
2234
- // buildFuncDecl builds SSA code for the function or method declared
2235
- // by decl in package pkg .
2268
+ // buildCreated does the BUILD phase for each function created by builder that is not yet BUILT.
2269
+ // Functions are built using buildFunction .
2236
2270
//
2237
- func (b * builder ) buildFuncDecl (pkg * Package , decl * ast.FuncDecl ) {
2238
- id := decl .Name
2239
- if isBlankIdent (id ) {
2240
- return // discard
2271
+ // May add types that require runtime type information to builder.
2272
+ //
2273
+ func (b * builder ) buildCreated () {
2274
+ for ; b .finished < b .created .Len (); b .finished ++ {
2275
+ fn := b .created .At (b .finished )
2276
+ b .buildFunction (fn )
2241
2277
}
2242
- fn := pkg .objects [pkg .info .Defs [id ]].(* Function )
2243
- if decl .Recv == nil && id .Name == "init" {
2244
- var v Call
2245
- v .Call .Value = fn
2246
- v .setType (types .NewTuple ())
2247
- pkg .init .emit (& v )
2278
+ }
2279
+
2280
+ // Adds any needed runtime type information for the created functions.
2281
+ //
2282
+ // May add newly CREATEd functions that may need to be built or runtime type information.
2283
+ //
2284
+ // EXCLUSIVE_LOCKS_ACQUIRED(prog.methodsMu)
2285
+ //
2286
+ func (b * builder ) needsRuntimeTypes () {
2287
+ if b .created .Len () == 0 {
2288
+ return
2248
2289
}
2249
- b .buildFunction (fn )
2290
+ prog := b .created .At (0 ).Prog
2291
+
2292
+ var rtypes []types.Type
2293
+ for ; b .rtypes < b .finished ; b .rtypes ++ {
2294
+ fn := b .created .At (b .rtypes )
2295
+ rtypes = append (rtypes , mayNeedRuntimeTypes (fn )... )
2296
+ }
2297
+
2298
+ // Calling prog.needMethodsOf(T) on a basic type T is a no-op.
2299
+ // Filter out the basic types to reduce acquiring prog.methodsMu.
2300
+ rtypes = nonbasicTypes (rtypes )
2301
+
2302
+ for _ , T := range rtypes {
2303
+ prog .needMethodsOf (T , b .created )
2304
+ }
2305
+ }
2306
+
2307
+ func (b * builder ) done () bool {
2308
+ return b .rtypes >= b .created .Len ()
2250
2309
}
2251
2310
2252
2311
// Build calls Package.Build for each package in prog.
@@ -2293,12 +2352,14 @@ func (p *Package) build() {
2293
2352
// that would require package creation in topological order.
2294
2353
for name , mem := range p .Members {
2295
2354
if ast .IsExported (name ) {
2296
- p .Prog .needMethodsOf (mem .Type ())
2355
+ p .Prog .needMethodsOf (mem .Type (), & p . created )
2297
2356
}
2298
2357
}
2299
2358
if p .Prog .mode & LogSource != 0 {
2300
2359
defer logStack ("build %s" , p )()
2301
2360
}
2361
+
2362
+ b := builder {created : & p .created }
2302
2363
init := p .init
2303
2364
init .startBody ()
2304
2365
@@ -2327,8 +2388,6 @@ func (p *Package) build() {
2327
2388
}
2328
2389
}
2329
2390
2330
- var b builder
2331
-
2332
2391
// Initialize package-level vars in correct order.
2333
2392
for _ , varinit := range p .info .InitOrder {
2334
2393
if init .Prog .mode & LogSource != 0 {
@@ -2356,13 +2415,18 @@ func (p *Package) build() {
2356
2415
}
2357
2416
}
2358
2417
2359
- // Build all package-level functions, init functions
2360
- // and methods, including unreachable/blank ones.
2361
- // We build them in source order, but it's not significant.
2418
+ // Call all of the declared init() functions in source order.
2362
2419
for _ , file := range p .files {
2363
2420
for _ , decl := range file .Decls {
2364
2421
if decl , ok := decl .(* ast.FuncDecl ); ok {
2365
- b .buildFuncDecl (p , decl )
2422
+ id := decl .Name
2423
+ if ! isBlankIdent (id ) && id .Name == "init" && decl .Recv == nil {
2424
+ fn := p .objects [p .info .Defs [id ]].(* Function )
2425
+ var v Call
2426
+ v .Call .Value = fn
2427
+ v .setType (types .NewTuple ())
2428
+ p .init .emit (& v )
2429
+ }
2366
2430
}
2367
2431
}
2368
2432
}
@@ -2374,8 +2438,28 @@ func (p *Package) build() {
2374
2438
}
2375
2439
init .emit (new (Return ))
2376
2440
init .finishBody ()
2441
+ init .done ()
2442
+
2443
+ // Build all CREATEd functions and add runtime types.
2444
+ // These Functions include package-level functions, init functions, methods, and synthetic (including unreachable/blank ones).
2445
+ // Builds any functions CREATEd while building this package.
2446
+ //
2447
+ // Initially the created functions for the package are:
2448
+ // [init, decl0, ... , declN]
2449
+ // Where decl0, ..., declN are declared functions in source order, but it's not significant.
2450
+ //
2451
+ // As these are built, more functions (function literals, wrappers, etc.) can be CREATEd.
2452
+ // Iterate until we reach a fixed point.
2453
+ //
2454
+ // Wait for init() to be BUILT as that cannot be built by buildFunction().
2455
+ //
2456
+ for ! b .done () {
2457
+ b .buildCreated () // build any CREATEd and not BUILT function. May add runtime types.
2458
+ b .needsRuntimeTypes () // Add all of the runtime type information. May CREATE Functions.
2459
+ }
2377
2460
2378
- p .info = nil // We no longer need ASTs or go/types deductions.
2461
+ p .info = nil // We no longer need ASTs or go/types deductions.
2462
+ p .created = nil // We no longer need created functions.
2379
2463
2380
2464
if p .Prog .mode & SanityCheckFunctions != 0 {
2381
2465
sanityCheckPackage (p )
0 commit comments