Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Issue 214] Exception signaling without helper methods #251

Merged
merged 5 commits into from
Jun 3, 2018

Conversation

clementbera
Copy link
Contributor

@clementbera clementbera commented May 22, 2018

This PR introduces the infrastructure to do exception signaling without relying on helper methods in the Newspeak code. Thereby, it addresses #214.

It introduces the ExceptionSignalingNode, which performs the message sends necessary to signal an exception.
In the interpreter, this allows us to have for instance code like this:

@Child ExceptionSignalingNode indexOutOfBounds;

// ...

indexOutOfBounds.signal(arr, idx);

Work with @daumayr.

This change does not yet fully optimize the exception signaling. For instance, it does not cache the exception class, which could avoid the message send for its lookup. However, this would need to be done very carefully, since the lookup is done via a normal message send, which could have side effects. Thus, it should only be optimized for well known and unproblematic cases.

[description updated by @smarr to be a summary of the change]

@smarr
Copy link
Owner

smarr commented May 22, 2018

For attribution purposes, I'd add a line like Co-authored-by: name <name@example.com> to the commit message, to attribute Dominik. /cc @daumayr

See
https://help.github.com/articles/creating-a-commit-with-multiple-authors/

There's also a compilation error: https://travis-ci.org/smarr/SOMns/jobs/382258342#L689

Copy link
Owner

@smarr smarr left a comment

Choose a reason for hiding this comment

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

Some comments and potential improvements.


private signalArgumentError: message = (
ArgumentError signalWith: message.
)
Copy link
Owner

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@Child protected ExpressionNode signalExceptionNode;
protected final SObject module;

public ExceptionSignalingNode(final String exceptionClassName,
Copy link
Owner

Choose a reason for hiding this comment

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

Hm, is that so common that it is worthwhile to have the standard parameter KernelObj.kernel?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There's a dozen senders, but we can remove it if you want to.

Copy link
Owner

Choose a reason for hiding this comment

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

How about a named factory method?
I'd prefer that over a constructor, because it would be more explicit.

So, perhaps createForKernel(..)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved to a factory as requested.

allArgs[0] = exceptionClass;
for (int i = 0; i < args.length; i++) {
allArgs[i + 1] = args[i];
}
Copy link
Owner

Choose a reason for hiding this comment

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

Would be nice to extract line 43-47 into a named method

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@@ -73,7 +98,8 @@ public SClass instantiateClass(final SObjectWithClass outerObj,
public static SClass instantiate(final SObjectWithClass outerObj,
final ClassFactory factory) {
SClass classObj = new SClass(outerObj, instantiateMetaclassClass(factory, outerObj));
return singalExceptionsIfFaultFoundElseReturnClassObject(outerObj, factory, classObj);
return signalExceptionsIfFaultFoundElseReturnClassObject(outerObj, factory, classObj,
floatingNotAValueThrower, floatingCannotBeValuesThrower);
Copy link
Owner

Choose a reason for hiding this comment

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

Hm, can we improve this?

Ideally, the nodes should come from the caller.
The @Specialization above could provide instance-specific nodes, and the other callers could pass them in from static fields, if really necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

}

@Child protected ExceptionSignalingNode thrower;
Copy link
Owner

Choose a reason for hiding this comment

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

Fields are ideally defined before the constructors

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

return this;
}

@Child protected ExceptionSignalingNode thrower;
Copy link
Owner

Choose a reason for hiding this comment

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

Please before constructor

return this;
}

@Child protected ExceptionSignalingNode thrower;
Copy link
Owner

Choose a reason for hiding this comment

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

Please before constructor

@Child ExceptionSignalingNode thrower;

@Override
public void signalException(final String message) {
Copy link
Owner

Choose a reason for hiding this comment

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

Hm, can this be done as a default method to avoid code duplication?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We can't.
We are not able to use a common superclass.
If we move the code out, methods such as insert are not visible anymore.

@@ -103,4 +103,5 @@ public final Object doException(final SBlock body, final SBlock ensureHandler) {
}
}
}

Copy link
Owner

Choose a reason for hiding this comment

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

unnecessary change

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Don't know how to remove that. CheckStyle added it for us I think.

CompilerAsserts.neverPartOfCompilation();
KernelObj.signalException("signalArgumentError:", "File access mode invalid, was: "
+ Objects.toString(mode) + " " + AccessModes.VALID_MODES);
this.accessMode = AccessModes.valueOf(mode.getString());
Copy link
Owner

Choose a reason for hiding this comment

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

I don't get this change. Where did the exception go?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the sender, so it can have the exceptionSignalNode.

Repository owner deleted a comment May 23, 2018
Copy link
Owner

@smarr smarr left a comment

Choose a reason for hiding this comment

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

@clementbera @daumayr I also just pushed a bunch of changes. They are mostly polish, stuff I didn't see from simple reviewing. Note, this is work in progress. Will continue later.

@@ -645,6 +645,7 @@ DAMAGE.>> *)
)
) : (
public signalWith: aMessage = (
vmMirror printStackTrace: nil.
Copy link
Owner

Choose a reason for hiding this comment

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

That's debugging code, we want to solve this not specific to an exception, but somewhat differently (there is no implementation of stack trace capturing at the moment)

} catch (NotAFileException e) {
PathPrims.signalFileNotFoundException(e.getMessage(),
"Path does not seem to be a file.");
"Path does not seem to be a file.", thrower);
Copy link
Owner

Choose a reason for hiding this comment

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

Hm, that's FileNotFound?

} catch (IOException e) {
PathPrims.signalIOException(e.getMessage());
PathPrims.signalIOException(e.getMessage(), thrower);
Copy link
Owner

Choose a reason for hiding this comment

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

And here the same thrower node is IOException? seems fishy

@smarr
Copy link
Owner

smarr commented May 28, 2018

@clementbera @daumayr think this here is a slightly nicer solution, because it avoids an interface: 52a0041

Also, I am going to change all thrower to use the exception name. Together with another change, the result reads nicely, for instance: argumentError.signal(...)

@smarr
Copy link
Owner

smarr commented May 28, 2018

Ok, now I see why you might have decided for a lazy approach to initialize those exception nodes.
They need the module, but the module might not yet be loaded. Hmpf.

@smarr
Copy link
Owner

smarr commented May 28, 2018

@daumayr @clementbera please review 8412ba6 carefully (see comment).
This might not be the smallest possible change. However, I consider it a useful exercise of some useful design choices and Truffle techniques. Delayed initialization can be achieved with node rewriting, which keeps the logic localized.

@smarr
Copy link
Owner

smarr commented May 28, 2018

Ok, I am now happy with this. I did a bunch of other changes and clean ups.
Before merging, I am going to squash most of this, since the history is pretty uninteresting and I prefer a easily understandable set of changes.

Please review carefully.

@smarr smarr added enhancement Improves the implementation with something noteworthy language-design Not everything is in the spec, sometimes, we need to decide what's best. labels May 28, 2018
@smarr smarr added this to the v0.7.0 milestone May 28, 2018
@daumayr
Copy link
Contributor

daumayr commented May 29, 2018

Looks good to me.
So replacing nodes is an option for lazy initialisation, I didn't know that.

…lingTruffleNode

- added JUnits tests for Files

Co-authored-by: Dominik Aumayr <daumayr162@gmail.com>
@smarr smarr force-pushed the issue-214-optimize-exception-signaling branch 2 times, most recently from 65110a6 to a2983fd Compare May 29, 2018 21:37
Copy link
Contributor Author

@clementbera clementbera left a comment

Choose a reason for hiding this comment

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

I think there are some issues, sometimes nodes are initialized with insert(), sometimes not. I guess they should all have insert. Theres a single place where renaming was not done. I annotated all of them. I wanted to change, but for some reasons I have way too many conflicts when I pull.

public ClassInstantiationNode(final MixinDefinition mixinDefinition) {
super(mixinDefinition);
notAValueThrower = insert(ExceptionSignalingNode.createNotAValueNode(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was not renamed (still named thrower)

@@ -88,6 +103,11 @@ public SClass instantiateClassWithNewClassFactory(final SObjectWithClass outerOb

public ObjectLiteralInstantiationNode(final MixinDefinition mixinDefinition) {
super(mixinDefinition);
notAValueThrower = ExceptionSignalingNode.createNotAValueNode(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was not renamed (thrower) and it seems the insert() function is missing.

@SuppressWarnings("unchecked")
public ValueCheckNode initialize(final SourceSection sourceSection) {
super.initialize(sourceSection);
notAValue = ExceptionSignalingNode.createNotAValueNode(sourceSection);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

It seems the insert() is missing.

@SuppressWarnings("unchecked")
public NewImmutableArrayNode initialize(final SourceSection sourceSection) {
super.initialize(sourceSection);
notAValue = ExceptionSignalingNode.createNotAValueNode(sourceSection);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

No insert()

@smarr
Copy link
Owner

smarr commented Jun 1, 2018

I think there are some issues, sometimes nodes are initialized with insert(), sometimes not. I guess they should all have insert. Theres a single place where renaming was not done. I annotated all of them.

Inserts are needed when the nodes are added to a method after the whole method was construct.
Or after the first activation? I am not entirely sure. At one point, all child nodes are adopted ("inserted") automatically.

So, strictly speaking insert() is only needed after that point.
And yes, there might be inconsistencies in the code currently.

I wanted to change, but for some reasons I have way too many conflicts when I pull.

As mentioned before, I started squashing commits that do not add helpful information to the history and only make it harder to understand why and how things changed (fixups, in-development bugs, other changes that are only side-effects of the development, and not relevant for the end result).

Signed-off-by: Stefan Marr <git@stefan-marr.de>
@smarr smarr force-pushed the issue-214-optimize-exception-signaling branch from ad93285 to ef3e9d9 Compare June 3, 2018 15:11
smarr added 3 commits June 3, 2018 16:27
Signed-off-by: Stefan Marr <git@stefan-marr.de>
- pre-allocate commonly used exception-related symbols, and use instead
  of strings
- rename execute to signal, and use directly
- consistently use factory methods for exception nodes
  - reduce extensive verbosity, they are static methods,
    context is provided by the class name
  - change name of parameters: they are selectors,
    could be other things beside classes
  - restructure to enable lazy initialization on first activation
    - this is necessary to resolve modules which are loaded after
      parsing a method
    - also allocate the message send nodes lazily to avoid impact on
      startup performance

- improve source section used for attribution to be the initializer
- use node initializer methods consistently
- remove ValuePrim, simply pass node instead
- avoid `thrower` as name, instead use the type of the exception
  that’s going to be throw. Reads nicer: `argumentError.signal(…)`

- remove unused code

Signed-off-by: Stefan Marr <git@stefan-marr.de>
Signed-off-by: Stefan Marr <git@stefan-marr.de>
@smarr smarr force-pushed the issue-214-optimize-exception-signaling branch from ef3e9d9 to 3406c63 Compare June 3, 2018 16:12
@smarr smarr changed the title Issue 214 optimize exception signaling [Issue 214] Exception signaling without helper methods Jun 3, 2018
@smarr
Copy link
Owner

smarr commented Jun 3, 2018

I finished the final cleanups, squashed the history where useful, and updated the issue title/description to explain the changes.

Note, there is another change hidden in here: the message send nodes for the exception handling are all allocated lazily now. There was some overhead on the startup performance, which is fixed by this.

Will merge once all tests/benchmarks passed.
I also included 3406c63 to add the performance note to SClass.isKindOf() (see #253).

@smarr smarr merged commit 574a634 into smarr:dev Jun 3, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Improves the implementation with something noteworthy language-design Not everything is in the spec, sometimes, we need to decide what's best.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants