From 35d155edfce64e8ba558f099f2695d7399177534 Mon Sep 17 00:00:00 2001 From: Tomasz Nguyen Date: Wed, 13 Dec 2023 13:11:59 +0000 Subject: [PATCH] fix: make static data variable threadsafe I've hit a bug developing a go parser and running multiple instances of it with t.Parallel() Turned out that staticData var was a global and would throw concurrent data access errors when running the test suite with -race This commit fixes it by doing the following: 1. turn ParserStaticData into a struct 2. Teach Init() to return a pointer to new instance of this struct 3. Teach Init() to initialize it upon construction I've been able to run 10000 concurrent parsers in this setup without having any performance/memory usage problem Signed-off-by: Tomasz Nguyen Signed-off-by: Tomasz Nguyen --- .../antlr/v4/tool/templates/codegen/Go/Go.stg | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tool/resources/org/antlr/v4/tool/templates/codegen/Go/Go.stg b/tool/resources/org/antlr/v4/tool/templates/codegen/Go/Go.stg index 19dcc3f4354..31aed396037 100644 --- a/tool/resources/org/antlr/v4/tool/templates/codegen/Go/Go.stg +++ b/tool/resources/org/antlr/v4/tool/templates/codegen/Go/Go.stg @@ -166,7 +166,7 @@ type struct { } -var ParserStaticData struct { +type ParserStaticData struct { once sync.Once serializedATN []int32 LiteralNames []string @@ -198,10 +198,9 @@ func ParserInit() { staticData.serializedATN = deserializer := antlr.NewATNDeserializer(nil) staticData.atn = deserializer.Deserialize(staticData.serializedATN) - atn := staticData.atn - staticData.decisionToDFA = make([]*antlr.DFA, len(atn.DecisionToState)) + staticData.decisionToDFA = make([]*antlr.DFA, len(staticData.atn.DecisionToState)) decisionToDFA := staticData.decisionToDFA - for index, state := range atn.DecisionToState { + for index, state := range staticData.atn.DecisionToState { decisionToDFA[index] = antlr.NewDFA(state, index) } } @@ -210,14 +209,15 @@ func ParserInit() { // static state used to implement the parser is lazily initialized during the first call to // New(). You can call this function if you wish to initialize the static state ahead // of time. -func Init() { - staticData := &ParserStaticData - staticData.once.Do(ParserInit) +func Init() *ParserStaticData { + staticData := &ParserStaticData{} + ParserInit(staticData) + return staticData } // New produces a new parser instance for the optional input antlr.TokenStream. func New(input antlr.TokenStream) * { - Init() + staticData := Init() this := new() this.BaseParser = antlr.NewBaseParser(input) staticData := &ParserStaticData