Skip to content

Conversation

@fingolfin
Copy link
Member

@fingolfin fingolfin commented Jan 1, 2020

This way, saving and restoring it becomes unnecessary. It also gets easier to reason about the behaviour of the code.

Note: the second commit in this PR should be removed before merging; it contains a gross #define hack which I added to make reviewing easier, by reducing the noise in which the actual changes are otherwise lost. It's still quite a bit, but hopefully manageable.

Continues work begun in PR #3805.

@fingolfin fingolfin added do not merge PRs which are not yet ready to be merged (e.g. submitted for discussion, or test results) topic: kernel release notes: not needed PRs introducing changes that are wholly irrelevant to the release notes labels Jan 1, 2020

struct ReaderState {

ScannerState s;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ScannerState becomes part of the ReaderState (I've intended to do it this way for quite some time now - finally it happens, yay!)

One way to make this perhaps slightly nicer, and avoid some of the diffs in this PR permanently (i.e. not just with my crappy HACK commit) would be to switch read.c to C++, and then make ReaderState into a "subclass" of ScannerState. This way, a ReaderState * can be passed to any function expecting a ScannerState.

But I have doubts whether that's enough to justify converting the whole file to C++... ?!

readTop = rs->ReadTop;
readTilde = rs->ReadTilde;
tilde = STATE(Tilde);
currLHSGVar = rs->CurrLHSGVar;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here something "real" happens: we avoid the need to backing up parts of the ReaderState (and we also avoid questions about why we just save those parts of the Reader, but not others... Now we "save" all of them, automatically.)

UInt currLHSGVar;
UInt userHasQuit;
syJmp_buf readJmpError;
UInt intrCoding;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I guess we should rename SavedReaderState to something else...

Note that I am thinking about moving STATE(IntrCoding) and friends into a new InterpreterState (which ultimately also would be stack allocated...)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was done in PR #3823 which also removed SavedReaderState

@coveralls
Copy link

coveralls commented Jan 1, 2020

Coverage Status

Coverage decreased (-0.0005%) to 84.729% when pulling ece4b25 on fingolfin:mh/ReaderState into a4a3764 on gap-system:master.

@fingolfin fingolfin added do not merge PRs which are not yet ready to be merged (e.g. submitted for discussion, or test results) and removed do not merge PRs which are not yet ready to be merged (e.g. submitted for discussion, or test results) labels Jan 6, 2020
{
return (struct ReaderState *)StateSlotsAtOffset(ReaderStateOffset);
}
typedef struct ReaderState ReaderState;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we can see that there was a (per-thread) instance of struct ReaderState inside the global GAPState (accessed here via StateSlotsAtOffset), and now isn't anymore. ReaderState used to refer to a helper function to access it; now ReaderState is an alias for struct ReaderState, and we instead pass a stack-allocated instance of struct ReaderState around via function arguments

** be declared forward.
*/
static void ReadExpr(ScannerState * s, TypSymbolSet follow, Char mode);
static void ReadExpr(ReaderState * rs, TypSymbolSet follow, Char mode);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From here on, we see a lot of changes identical to this: instead of just a ScannerState, we now pass around a ReaderState (which contains a ScannerState).

GAP_ASSERT(ReaderState()->CurrentGlobalForLoopDepth);
ReaderState()->CurrentGlobalForLoopDepth--;
GAP_ASSERT(rs->CurrentGlobalForLoopDepth);
rs->CurrentGlobalForLoopDepth--;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also see a lot of changes identical to this: instead of using ReaderState(), we now use a ReaderState instance named rs which the callers passes down to us.

else if (s->Symbol == S_LPAREN) {
Match(s, S_LPAREN, "(", S_COMMA | follow);
ReadExpr(s, follow, 'r');
ReadExpr(rs, follow, 'r');
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aaaand we also see a lot of these: instead of passing a ScannerState named s, we pass on a ReaderState called rs.

src/read.c Outdated


// HACK
#define s (&rs->s)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This HACK is part of the second commit (which is meant to be dropped before merging this), and only is here for review purposes, to reduce the number of meaningless diffs: where before we directly accessed a ScannerState named s, we now instead need to get the ScannerState from inside the ReaderState called rs. To hide this, we use this #define.

memset(s, 0, sizeof(ScannerState));
ReaderState reader;
ReaderState * volatile rs = &reader;
memset(rs, 0, sizeof(ReaderState));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Up to here, basically nothing happened besides the things I explicitly pointed out; 99% of the changes are change ScannerState * s -> ReaderState * rs and related changes.

Here now we allocate a ReaderState on the stack, and zero it.

Copy link
Contributor

@ChrisJefferson ChrisJefferson Jan 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we do ReaderState reader = {0} instead?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually tried this first, but it caused compiler warnings on Travis. I couldn't reproduce those on macOS or on my Ubuntu, probably because my versions of GCC were too new.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem. Stupid travis, but it's not worth adding code which will have warnings.

rs->ReadTop = readTop;
rs->ReadTilde = readTilde;
STATE(Tilde) = tilde;
rs->CurrLHSGVar = currLHSGVar;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Real change: since we freshly allocated the ReaderState on the stack, there is no need to "restore" its content before returning.

rs->ReadTop = readTop;
rs->ReadTilde = readTilde;
STATE(Tilde) = tilde;
rs->CurrLHSGVar = currLHSGVar;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Real change: since we freshly allocated the ReaderState on the stack, there is no need to "restore" its content before returning.

}

GAP_ASSERT(rs->LoopNesting == 0);
nr = ReadStats(rs, S_SEMICOLON | S_EOF);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Real change: since we freshly allocated the ReaderState on the stack, there is no need to "restore" its LoopNesting member here.

readTop = rs->ReadTop;
readTilde = rs->ReadTilde;
tilde = STATE(Tilde);
currLHSGVar = rs->CurrLHSGVar;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Real change: since we freshly allocated the ReaderState on the stack, there is no need to "preserve" its "previous" content.

memset(s, 0, sizeof(ScannerState));
ReaderState reader;
ReaderState * volatile rs = &reader;
memset(rs, 0, sizeof(ReaderState));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Real change: we allocate a ReaderState on the stack and zero it.

ReaderState()->StackNams = NEW_PLIST( T_PLIST, 16 );
ReaderState()->ReadTop = 0;
ReaderState()->ReadTilde = 0;
ReaderState()->CurrLHSGVar = 0;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to preserve or restore these, as we stack allocate the ReaderState for each use freshly on the stack.

ReaderState()->StackNams = s->stackNams;
ReaderState()->ReadTop = s->readTop;
ReaderState()->ReadTilde = s->readTilde;
ReaderState()->CurrLHSGVar = s->currLHSGVar;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to preserve or restore these, as we stack allocate the ReaderState for each use freshly on the stack.

StructInitInfo * module )
{
#if !defined(HPCGAP)
InitGlobalBag(&ReaderState()->StackNams, "src/read.c:StackNams");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StackNams now is in a ReaderState instance on the stack, and hence our stack scanning code ensure it is not garbage collected. So this line can go.

ReaderState()->ReadTop = 0;
ReaderState()->ReadTilde = 0;
ReaderState()->CurrLHSGVar = 0;
ReaderState()->CurrentGlobalForLoopDepth = 0;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no per-thread ReaderState as part of the GAPState anymore, so the above can go.

.initKernel = InitKernel,

.moduleStateSize = sizeof(struct ReaderState),
.moduleStateOffsetPtr = &ReaderStateOffset,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no per-thread ReaderState as part of the GAPState anymore, so the above can go.

@fingolfin
Copy link
Member Author

I've now left a bunch of comments that try to explain the changes in-depth. Perhaps that's enough to make some people dare to look at it, e.g. @DominikBernhardt @wucas @flyingapfopenguin @ChrisJefferson

Copy link
Contributor

@ChrisJefferson ChrisJefferson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One comment, about removing memset and using {0} instead (which isn't required). There are a couple of places this change would be made.

Copy link
Member

@wilfwilson wilfwilson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the hand-holding comments Max.

In case you've not noticed, this PR now has conflicts with master.

This way, saving and restoring it becomes unnecessary. It also gets easier to
reason about the behaviour of the code.
@fingolfin fingolfin merged commit acb61ab into gap-system:master Jan 9, 2020
@fingolfin fingolfin deleted the mh/ReaderState branch January 9, 2020 06:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do not merge PRs which are not yet ready to be merged (e.g. submitted for discussion, or test results) release notes: not needed PRs introducing changes that are wholly irrelevant to the release notes topic: kernel

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants