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

Exposing a new JSRT method to get additional information about exceptions #2936

Merged

Conversation

MSLaguana
Copy link
Contributor

This information includes the source file and line/column position of where the exception
came from, as well as the actual source content of the line.

The motivation for this method is for node to print it out on uncaught exceptions.

/// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise.
/// </returns>
CHAKRA_API
JsGetAndClearExceptionWithMetadata(
Copy link
Collaborator

Choose a reason for hiding this comment

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

JsGetAndClearExceptionWithMetadata [](start = 0, length = 34)

@liminzhu Should this be in ChakraCommon.h instead of core only?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

At the moment this is still experimental and not yet officially supported, which is why I put it in ChakraCore.h

@@ -2511,6 +2512,92 @@ CHAKRA_API JsHasException(_Out_ bool *hasException)
return JsNoError;
}

CHAKRA_API JsGetAndClearExceptionWithMetadata(_Out_ JsValueRef *metadata)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Apart from the return part, this implementation looks like an exact match to JsGetAndClearException implementation below. In order not to duplicate, could it be better to define a common function and make these two public methods using that?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

They do share a common prelude, but they do slightly different things for TTD, and I need to reference a few things from the prelude in the latter part of this function like the scriptContext and the recordedException. We could split the prelude out into a common function but it would be very specific.

Copy link
Contributor

Choose a reason for hiding this comment

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

did you consider using ContextAPIWrapper, it does bunch of checks already which you are performing in this function?


In reply to: 115546477 [](ancestors = 115546477)

@obastemur
Copy link
Collaborator

Is it possible to add a test under test/native-tests using this new interface? or using it from CH and a test touching it somehow? ATM CI doesn't test this new interface and if we break it later, we won't know.

@MSLaguana
Copy link
Contributor Author

I've extended one of the tests in JsRTApiTest.cpp to cover the new method.

@jianchun
Copy link

jianchun commented May 9, 2017

@MSLaguana A thought of API design. Instead of this, how about keep using the existing JsGetAndClearException, but add a new API like JsGetExceptionMetaData(exception, ...) in which to populate the info you needed? That'll avoid deprecating API and duplicating code.

@MSLaguana
Copy link
Contributor Author

How do you see that flow working? The additional information that we need is accessed through the JavascriptExceptionObject which is cleared and forgotten in JsGetAndClearException. It isn't a javascript value so I don't believe that I can attach it to the exception object, which is a javascript value (and may be any javascript value since it is whatever was thrown).

@jianchun
Copy link

jianchun commented May 9, 2017

How do you see that flow working? The additional information that we need is accessed through the JavascriptExceptionObject which is cleared and forgotten in JsGetAndClearException. It isn't a javascript value so I don't believe that I can attach it to the exception object, which is a javascript value (and may be any javascript value since it is whatever was thrown).

Indeed that is a problem. I can only think of an ugly workaround that may have problems (use an InternalProperty to store the exceptionRecord in the thrownObject. Give up, or do ToObject on thrownObject if it is a tagged number.)

Your approach seems fine.

@liminzhu
Copy link
Collaborator

liminzhu commented May 10, 2017

What's the difference in behavior between JsGetAndClearExceptionWithMetadata and JsGetAndClearException? Is the former exactly hte same as latter except for extra metadata info on the returned object?

/// to be in the exception state and resets the exception state for that runtime. The metadata
/// includes a reference to the exception itself.
/// </summary>
/// <remarks>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you lay out the returned metadata object in <remarks>? I've always hated that I've no clue what's in exception of JsGetAndClearException without looking into source code.

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.

}
startCharOffset = cache->GetCharacterOffsetForLine(line, &startByteOffset);

if (line + 1 >= cache->GetLineCount())
Copy link
Contributor

Choose a reason for hiding this comment

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

can you use unit32math helper ?

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.

// The offsets above point to the start of the following line,
// while we need to find the end of the current line.
// To do so, just step back over the preceeding newline character(s)
if (functionSource[endByteOffset - 1] == _u('\n'))
Copy link
Contributor

Choose a reason for hiding this comment

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

could this be 0 ? assertorfailfast in beginning?

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 must not be 0 since it is the offset for at least the second line. However, the next check could potentially be 0, so I've added a check there.


Js::Utf8SourceInfo* sourceInfo = functionBody->GetUtf8SourceInfo();
sourceInfo->EnsureLineOffsetCache();
JsUtil::LineOffsetCache<Recycler> *cache = sourceInfo->GetLineOffsetCache();
Copy link
Contributor

Choose a reason for hiding this comment

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

Did you consider to move and encapsulate this to functionbody?


if (line >= cache->GetLineCount())
{
return false;
Copy link
Contributor

Choose a reason for hiding this comment

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

if we return false here, all the setproperty we have done above is wasted, isn't it? make sense to move this to top of the function.

if (functionBody == nullptr)
{
// This is probably a parse error. We can get the error location metadata from the thrown object.
Js::JavascriptExceptionMetadata::PopulateMetadataFromCompileException(exceptionMetadata, exception, scriptContext);
Copy link
Contributor

Choose a reason for hiding this comment

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

do you have the test case for this syntax error part in the jsRTApiTest?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I do now.

@@ -751,6 +754,39 @@ namespace JsRTApiTest
REQUIRE(JsSetException(exception) == JsNoError);
REQUIRE(JsHasException(&value) == JsNoError);
CHECK(value == true);

REQUIRE(JsGetAndClearExceptionWithMetadata(&exceptionMetadata) == JsNoError);
Copy link
Contributor

Choose a reason for hiding this comment

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

would be nice to verify this API in the case where there is no exception thrown?

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, which required some fixes in the JSRT functions.

@MSLaguana
Copy link
Contributor Author

@liminzhu JsGetAndClearException returns the thrown object from an exception while also clearing the current exception, and exposes no other information. JsGetAndClearExceptionWithMetadata has the same side effect of clearing the current exception, but returns a javascript object which has the thrown object as a property (the exception property) as well as other information: line number, column number, length, line of source code, and script name.

@liminzhu
Copy link
Collaborator

@MSLaguana gotcha. Is there any reason to use the old API when the new one's added? From an API design perspective, how do you feel about using and old API instead and piling new properties on the returned err object?

@MSLaguana
Copy link
Contributor Author

If you only care about the thrown object, then it's slightly cheaper to invoke the original method, but once this is accepted then I'll be changing node-chakracore to use only the new method since it always wants the additional information.

I would have preferred to re-use the previous method, but that's not possible. The object returned in the original method is the thrown javascript object, which can be any javascript object including a number, so it may not be something with properties (e.g. it may be a number).

@liminzhu
Copy link
Collaborator

@MSLaguana makes sense. Thanks for the explanation.

else
{
// This should not be possible
return false;
Copy link
Contributor

Choose a reason for hiding this comment

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

assert here, just to catch those issues?


LPCUTF8 functionSource = sourceInfo->GetSource(_u("Jsrt::JsExperimentalGetAndClearExceptionWithMetadata"));

charcount_t startByteOffset;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: initialize locals.

charcount_t endCharOffset;


startCharOffset = cache->GetCharacterOffsetForLine(line, &startByteOffset);
Copy link
Contributor

Choose a reason for hiding this comment

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

did you consider moving this whole thing to function body and encapsulate there?

@akroshg
Copy link
Contributor

akroshg commented May 15, 2017

:shipit:

Copy link
Contributor

@kfarnung kfarnung left a comment

Choose a reason for hiding this comment

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

🚢

…ions

This information includes the source file and line/column position of where the exception
came from, as well as the actual source content of the line.
@MSLaguana MSLaguana force-pushed the exposeExceptionMetadataR20 branch from 6b1731f to 84d61ad Compare May 15, 2017 18:52
@chakrabot chakrabot merged commit 84d61ad into chakra-core:release/2.0 May 15, 2017
chakrabot pushed a commit that referenced this pull request May 15, 2017
… information about exceptions

Merge pull request #2936 from MSLaguana:exposeExceptionMetadataR20

This information includes the source file and line/column position of where the exception
came from, as well as the actual source content of the line.

The motivation for this method is for node to print it out on uncaught exceptions.
chakrabot pushed a commit that referenced this pull request May 15, 2017
…et additional information about exceptions

Merge pull request #2936 from MSLaguana:exposeExceptionMetadataR20

This information includes the source file and line/column position of where the exception
came from, as well as the actual source content of the line.

The motivation for this method is for node to print it out on uncaught exceptions.
@MSLaguana MSLaguana deleted the exposeExceptionMetadataR20 branch May 16, 2017 00:05
@liminzhu
Copy link
Collaborator

Added API reference in wiki. Please update them if needed in the future.

https://github.com/Microsoft/ChakraCore/wiki/JsGetAndClearExceptionWithMetadata

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants