-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
Exposing a new JSRT method to get additional information about exceptions #2936
Conversation
/// The code <c>JsNoError</c> if the operation succeeded, a failure code otherwise. | ||
/// </returns> | ||
CHAKRA_API | ||
JsGetAndClearExceptionWithMetadata( |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
lib/Jsrt/Jsrt.cpp
Outdated
@@ -2511,6 +2512,92 @@ CHAKRA_API JsHasException(_Out_ bool *hasException) | |||
return JsNoError; | |||
} | |||
|
|||
CHAKRA_API JsGetAndClearExceptionWithMetadata(_Out_ JsValueRef *metadata) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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)
Is it possible to add a test under |
I've extended one of the tests in |
@MSLaguana A thought of API design. Instead of this, how about keep using the existing |
How do you see that flow working? The additional information that we need is accessed through the |
Indeed that is a problem. I can only think of an ugly workaround that may have problems (use an Your approach seems fine. |
What's the difference in behavior between |
/// 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> |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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()) |
There was a problem hiding this comment.
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 ?
There was a problem hiding this comment.
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')) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
@liminzhu |
@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? |
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). |
@MSLaguana makes sense. Thanks for the explanation. |
else | ||
{ | ||
// This should not be possible | ||
return false; |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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?
There was a problem hiding this 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.
6b1731f
to
84d61ad
Compare
… 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.
…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.
Added API reference in wiki. Please update them if needed in the future. |
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.