@@ -79,6 +79,8 @@ type Decl struct {
7979 // that it can be resumed after a blocking operation completes without
8080 // blocking the main thread in the meantime.
8181 Blocking bool
82+ // ForGeneric inidicates this decl is for a generic function or type.
83+ ForGeneric bool
8284}
8385
8486// minify returns a copy of Decl with unnecessary whitespace removed from the
@@ -101,6 +103,14 @@ func (d *Decl) Dce() *dce.Info {
101103 return & d .DCEInfo
102104}
103105
106+ func (fc * funcContext ) getCachedDecl (fullname string ) * Decl {
107+ return fc .pkgCtx .declCache .GetDecl (fullname )
108+ }
109+
110+ func (fc * funcContext ) putCachedDecl (d * Decl ) {
111+ fc .pkgCtx .declCache .PutDecl (d )
112+ }
113+
104114// topLevelObjects extracts package-level variables, functions and named types
105115// from the package AST.
106116func (fc * funcContext ) topLevelObjects (srcs * sources.Sources ) (vars []* types.Var , functions []* ast.FuncDecl , typeNames typesutil.TypeNames ) {
@@ -183,14 +193,20 @@ func (fc *funcContext) importDecls() (importedPaths []string, importDecls []*Dec
183193
184194// newImportDecl registers the imported package and returns a Decl instance for it.
185195func (fc * funcContext ) newImportDecl (importedPkg * types.Package ) * Decl {
196+ fullName := importDeclFullName (importedPkg )
197+ if d := fc .getCachedDecl (fullName ); d != nil {
198+ return d
199+ }
200+
186201 pkgVar := fc .importedPkgVar (importedPkg )
187202 d := & Decl {
188- FullName : importDeclFullName ( importedPkg ) ,
203+ FullName : fullName ,
189204 Vars : []string {pkgVar },
190205 ImportCode : []byte (fmt .Sprintf ("\t %s = $packages[\" %s\" ];\n " , pkgVar , importedPkg .Path ())),
191206 InitCode : fc .CatchOutput (1 , func () { fc .translateStmt (fc .importInitializer (importedPkg .Path ()), nil ) }),
192207 }
193208 d .Dce ().SetAsAlive ()
209+ fc .putCachedDecl (d )
194210 return d
195211}
196212
@@ -250,10 +266,12 @@ func (fc *funcContext) varDecls(vars []*types.Var) []*Decl {
250266// newVarDecl creates a new Decl describing a variable, given an explicit
251267// initializer.
252268func (fc * funcContext ) newVarDecl (init * types.Initializer ) * Decl {
253- d := & Decl {
254- FullName : varDeclFullName (init ),
269+ fullName := varDeclFullName (init )
270+ if d := fc .getCachedDecl (fullName ); d != nil {
271+ return d
255272 }
256273
274+ d := & Decl {FullName : fullName }
257275 assignLHS := []ast.Expr {}
258276 for _ , o := range init .Lhs {
259277 assignLHS = append (assignLHS , fc .newIdentFor (o ))
@@ -289,6 +307,7 @@ func (fc *funcContext) newVarDecl(init *types.Initializer) *Decl {
289307 if len (init .Lhs ) != 1 || analysis .HasSideEffect (init .Rhs , fc .pkgCtx .Info .Info ) {
290308 d .Dce ().SetAsAlive ()
291309 }
310+ fc .putCachedDecl (d )
292311 return d
293312}
294313
@@ -313,31 +332,15 @@ func (fc *funcContext) funcDecls(functions []*ast.FuncDecl) ([]*Decl, error) {
313332 // Auxiliary decl shared by all instances of the function that defines
314333 // package-level variable by which they all are referenced,
315334 // e.g. init functions and instances of generic functions.
316- objName := fc .objectName (o )
317- generic := len (instances ) > 1 || ! instances [0 ].IsTrivial ()
318- varName := objName
319- if generic {
320- varName += ` = []`
321- }
322- varDecl := & Decl {
323- FullName : funcVarDeclFullName (o ),
324- Vars : []string {varName },
325- }
326- varDecl .Dce ().SetName (o , nil , nil )
327- if generic && o .Exported () {
328- varDecl .ExportFuncCode = fc .CatchOutput (1 , func () {
329- fc .Printf ("$pkg.%s = %s;" , encodeIdent (fun .Name .Name ), objName )
330- })
331- }
332- funcDecls = append (funcDecls , varDecl )
335+ funcDecls = append (funcDecls , fc .newFuncVarDecl (fun , o , instances ))
333336 }
334337
335338 for _ , inst := range instances {
336339 funcDecls = append (funcDecls , fc .newFuncDecl (fun , inst ))
340+ }
337341
338- if o .Name () == "main" {
339- mainFunc = o // main() function candidate.
340- }
342+ if o .Name () == "main" {
343+ mainFunc = o // main() function candidate.
341344 }
342345 }
343346 if fc .pkgCtx .isMain () {
@@ -347,21 +350,69 @@ func (fc *funcContext) funcDecls(functions []*ast.FuncDecl) ([]*Decl, error) {
347350 // Add a special Decl for invoking main() function after the program has
348351 // been initialized. It must come after all other functions, especially all
349352 // init() functions, otherwise main() will be invoked too early.
350- funcDecls = append (funcDecls , & Decl {
351- FullName : mainFuncDeclFullName (),
352- InitCode : fc .CatchOutput (1 , func () { fc .translateStmt (fc .callMainFunc (mainFunc ), nil ) }),
353- })
353+ funcDecls = append (funcDecls , fc .newCallMainFuncDecl (mainFunc ))
354354 }
355355 return funcDecls , nil
356356}
357357
358+ func (fc * funcContext ) newFuncVarDecl (fun * ast.FuncDecl , o * types.Func , instances []typeparams.Instance ) * Decl {
359+ fullName := funcVarDeclFullName (o )
360+ if varDecl := fc .getCachedDecl (fullName ); varDecl != nil {
361+ return varDecl
362+ }
363+
364+ objName := fc .objectName (o )
365+ generic := len (instances ) > 1 || ! instances [0 ].IsTrivial ()
366+
367+ varName := objName
368+ if generic {
369+ varName += ` = []`
370+ }
371+
372+ varDecl := & Decl {
373+ FullName : fullName ,
374+ Vars : []string {varName },
375+ ForGeneric : generic ,
376+ }
377+ varDecl .Dce ().SetName (o , nil , nil )
378+
379+ if generic && o .Exported () {
380+ varDecl .ExportFuncCode = fc .CatchOutput (1 , func () {
381+ fc .Printf ("$pkg.%s = %s;" , encodeIdent (fun .Name .Name ), objName )
382+ })
383+ }
384+
385+ fc .putCachedDecl (varDecl )
386+ return varDecl
387+ }
388+
389+ func (fc * funcContext ) newCallMainFuncDecl (mainFunc * types.Func ) * Decl {
390+ fullName := mainFuncDeclFullName ()
391+ if d := fc .getCachedDecl (fullName ); d != nil {
392+ return d
393+ }
394+
395+ d := & Decl {
396+ FullName : fullName ,
397+ InitCode : fc .CatchOutput (1 , func () { fc .translateStmt (fc .callMainFunc (mainFunc ), nil ) }),
398+ }
399+ fc .putCachedDecl (d )
400+ return d
401+ }
402+
358403// newFuncDecl returns a Decl that defines a package-level function or a method.
359404func (fc * funcContext ) newFuncDecl (fun * ast.FuncDecl , inst typeparams.Instance ) * Decl {
405+ fullName := funcDeclFullName (inst )
406+ if d := fc .getCachedDecl (fullName ); d != nil {
407+ return d
408+ }
409+
360410 o := fc .pkgCtx .Defs [fun .Name ].(* types.Func )
361411 d := & Decl {
362- FullName : funcDeclFullName ( inst ) ,
412+ FullName : fullName ,
363413 Blocking : fc .pkgCtx .IsBlocking (inst ),
364414 LinkingName : symbol .New (o ),
415+ ForGeneric : ! inst .IsTrivial (),
365416 }
366417 d .Dce ().SetName (o , inst .TNest , inst .TArgs )
367418
@@ -384,6 +435,8 @@ func (fc *funcContext) newFuncDecl(fun *ast.FuncDecl, inst typeparams.Instance)
384435 fc .pkgCtx .CollectDCEDeps (d , func () {
385436 d .FuncDeclCode = fc .namedFuncContext (inst ).translateTopLevelFunction (fun )
386437 })
438+
439+ fc .putCachedDecl (d )
387440 return d
388441}
389442
@@ -460,28 +513,41 @@ func (fc *funcContext) namedTypeDecls(typeNames typesutil.TypeNames) ([]*Decl, e
460513// of the type, keyed by the type argument combination. Otherwise it contains
461514// the type definition directly.
462515func (fc * funcContext ) newNamedTypeVarDecl (obj * types.TypeName ) * Decl {
516+ fullName := typeVarDeclFullName (obj )
517+ if varDecl := fc .getCachedDecl (fullName ); varDecl != nil {
518+ return varDecl
519+ }
520+
463521 name := fc .objectName (obj )
464522 generic := fc .pkgCtx .instanceSet .Pkg (obj .Pkg ()).ObjHasInstances (obj )
465523 varName := name
466524 if generic {
467525 varName += ` = []`
468526 }
469527 varDecl := & Decl {
470- FullName : typeVarDeclFullName (obj ),
471- Vars : []string {varName },
528+ FullName : fullName ,
529+ Vars : []string {varName },
530+ ForGeneric : generic ,
472531 }
473532 varDecl .Dce ().SetName (obj , nil , nil )
474533 if isPkgLevel (obj ) {
475534 varDecl .ExportTypeCode = fc .CatchOutput (0 , func () {
476535 fc .Printf ("$pkg.%s = %s;" , encodeIdent (obj .Name ()), name )
477536 })
478537 }
538+
539+ fc .putCachedDecl (varDecl )
479540 return varDecl
480541}
481542
482543// newNamedTypeInstDecl returns a Decl that represents an instantiation of a
483544// named Go type.
484545func (fc * funcContext ) newNamedTypeInstDecl (inst typeparams.Instance ) (* Decl , error ) {
546+ fullName := typeDeclFullName (inst )
547+ if d := fc .getCachedDecl (fullName ); d != nil {
548+ return d , nil
549+ }
550+
485551 originType := inst .Object .Type ().(* types.Named )
486552
487553 fc .typeResolver = typeparams .NewResolver (fc .pkgCtx .typesCtx , inst )
@@ -501,7 +567,8 @@ func (fc *funcContext) newNamedTypeInstDecl(inst typeparams.Instance) (*Decl, er
501567
502568 underlying := instanceType .Underlying ()
503569 d := & Decl {
504- FullName : typeDeclFullName (inst ),
570+ FullName : fullName ,
571+ ForGeneric : ! inst .IsTrivial (),
505572 }
506573 d .Dce ().SetName (inst .Object , inst .TNest , inst .TArgs )
507574 fc .pkgCtx .CollectDCEDeps (d , func () {
@@ -559,6 +626,8 @@ func (fc *funcContext) newNamedTypeInstDecl(inst typeparams.Instance) (*Decl, er
559626 })
560627 }
561628 })
629+
630+ fc .putCachedDecl (d )
562631 return d , nil
563632}
564633
@@ -625,14 +694,21 @@ func (fc *funcContext) anonTypeDecls(anonTypes []*types.TypeName) []*Decl {
625694 }
626695 decls := []* Decl {}
627696 for _ , t := range anonTypes {
697+ fullName := anonTypeDeclFullName (t )
698+ if d := fc .getCachedDecl (fullName ); d != nil {
699+ decls = append (decls , d )
700+ continue
701+ }
702+
628703 d := & Decl {
629- FullName : anonTypeDeclFullName ( t ) ,
704+ FullName : fullName ,
630705 Vars : []string {t .Name ()},
631706 }
632707 d .Dce ().SetName (t , nil , nil )
633708 fc .pkgCtx .CollectDCEDeps (d , func () {
634709 d .AnonTypeDeclCode = []byte (fmt .Sprintf ("\t \t %s = $%sType(%s);\n " , t .Name (), strings .ToLower (typeKind (t .Type ())[5 :]), fc .initArgs (t .Type ())))
635710 })
711+ fc .putCachedDecl (d )
636712 decls = append (decls , d )
637713 }
638714 return decls
0 commit comments