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

[WIP] Add promise.any #6301

Closed
wants to merge 11 commits into from
Closed

Conversation

Kingwl
Copy link
Contributor

@Kingwl Kingwl commented Oct 8, 2019

WIP, not finally patch

  • AggregateError
  • Promise.any
  • tests

FIxes #6299

@Kingwl Kingwl changed the title [WIP] Add promise.any [WIP][NOT READY] Add promise.any Oct 8, 2019
@rhuanjl
Copy link
Collaborator

rhuanjl commented Oct 8, 2019

One note to help you - the test failures are because the self-hosted Javascript for JsBuiltins and INTL needs to be regenerated (a side effect of having added the ENTRY for any to JnDirectFields.h).

To fix this you'll need to run the script called RegenAllByteCode.cmd it will create new bytecode headers you'll need to commit.

@Kingwl
Copy link
Contributor Author

Kingwl commented Oct 8, 2019

@rhuanjl Thanks, I realized that.

@rhuanjl
Copy link
Collaborator

rhuanjl commented Oct 8, 2019

The script should have given you 8 files - it appears you only checked in 4 of them.

@Kingwl
Copy link
Contributor Author

Kingwl commented Oct 13, 2019

Hi, I think i need some help...

I have several questions:

  1. What is the 'internal slot'? IMO, Could I think of it as member of some c++ object in runtime?
  2. If 1 is current, Could I simply add a member into JavascriptError ? or extend that one?
  3. What is The List type in ChakraCore, Could I think of it as JavascriptArray?

Thanks

@rhuanjl
Copy link
Collaborator

rhuanjl commented Oct 13, 2019

  1. an internal slot from the JS spec = a property that can't be accessed from javascript (but can be accessed within runtime methods when needed) - normally done in CC by adding a property/member to the relevant C++ class
  2. not sure what you're asking in 2 - depends what internal slot you need to add
  3. If the spec asks for a list as an internal slot I'd reccomend using something based on ChakraCore's SList type - look at how JavascriptPromiseReactionList is done (search for that in JavascriptPromise.cpp and JavascriptPromise.h as a model to base off of)

@Kingwl
Copy link
Contributor Author

Kingwl commented Oct 14, 2019

@rhuanjl Thank you for your help!

@zenparsing
Copy link
Contributor

@Kingwl In addition to what @rhuanjl says, I think it would be better if we could subclass JavascriptError instead of adding the "errors" list directly to JavascriptError. I'm not sure how difficult that will be, though, given that we aren't currently subclassing JavascriptError (and we are currently using a lot of macros for error types, which may or may not work for a subclass).

Also, thanks for working on this one!

@Kingwl
Copy link
Contributor Author

Kingwl commented Oct 14, 2019

@zenparsing Thanks for the response
BTW have we got some existed way to regen bytecode that not on windows?

@rhuanjl
Copy link
Collaborator

rhuanjl commented Oct 14, 2019

The scripts that regen bytecode only work on windows BUT you could fairly easily hack it to work on macOS or Linux for testing BUT not for submitting because you need to submit updated bytecode for x64 and x86 - generating the x86 bytecode requires an x86 build of CC and currently on macOS and Linux you can only do x64 builds.

@Kingwl
Copy link
Contributor Author

Kingwl commented Oct 27, 2019

It's too hard to (seems) make that work...
I'll do some refect and add more test case soon...

@Kingwl Kingwl marked this pull request as ready for review October 27, 2019 12:25
@Kingwl Kingwl changed the title [WIP][NOT READY] Add promise.any [WIP] Add promise.any Oct 27, 2019
Copy link
Collaborator

@rhuanjl rhuanjl left a comment

Choose a reason for hiding this comment

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

Thank you for what you've done here, this is an amazing effort. I hope you'd like to continue to work on it? I'm sorry for the big delay from October - the future ownership of ChakraCore is transitioning, see #6384 for more details.

I've done an initial review - and left some comments, additionally:

  1. some tests for AggregateError when used on its own are needed
  2. I've not been through the time travel debug code yet - we'll also need TTD behaviour tests, though could potentially submit this with TTD as a pending/todo part.

@@ -2139,6 +2139,19 @@ using namespace Js;
return TRUE;
}

JavascriptArray* JavascriptOperators::IterableToList(RecyclableObject* items, ScriptContext* scriptContext) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

As far as I can see this is only used once, could you just do the steps inline without making a new method for it?

return pError;
}

void __declspec(noreturn) JavascriptAggregateError::ThrowAggregateError(ScriptContext* scriptContext, RecyclableObject* errors, int32 hCode, EXCEPINFO* pei)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Do we need all these variants for ThrowAggregateError? Where are they used?

@@ -484,6 +582,12 @@ namespace Js
pError->m_errorType = errorType;
}

void JavascriptAggregateError::SetErrorsProperties(JavascriptAggregateError* pError, RecyclableObject* errors)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could these steps be inlined when used rather than being a new method, considering how short it is?

JavascriptLibrary* library = scriptContext->GetLibrary();
JavascriptAggregateError* thisError = VarTo<JavascriptAggregateError>(args[0]);

RecyclableObject* iterator = JavascriptOperators::GetIterator(thisError->GetErrors(), scriptContext);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should do a nullptr check on the errors property - and return a 0 length array if errors is nullptr.

Var newTarget = args.GetNewTarget();
RecyclableObject* errors = args.Info.Count > 1 ? JavascriptOperators::IterableToList(VarTo<RecyclableObject>(args[1]), scriptContext) : library->CreateArray(0);
Var message = args.Info.Count > 2 ? args[2] : library->GetUndefined();
pError->SetErrors(errors);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should make the errors a nullptr if length would be 0 and skip allocating the array - though will need to add a nullptr check when using it (though that should be added for safety anyway).

lib/Runtime/Library/JavascriptLibrary.cpp Show resolved Hide resolved

AUTO_TAG_NATIVE_LIBRARY_ENTRY(function, callInfo, _u("Promise.any"));

// 1. Let C be the this value.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should either run the Spec comments all the way through or emit them entirely. I favour having them all the way through if you can.

// 3. Let promiseCapability be NewPromiseCapability(C).
JavascriptPromiseCapability* promiseCapability = NewPromiseCapability(constructor, scriptContext);

RecyclableObject* constructorObject = VarTo<RecyclableObject>(constructor);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could use UnsafeVarTo (excludes a type check) as you've implicitly checked that this conversion will work with the IsObject check above - though perhaps move this up to be straight under the if to make that obvious.

}

void JavascriptPromiseAnyRejectElementFunction::SetAlreadyCalled(const bool is)
{
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: if using a setter for this no need for a parameter as you'll only ever call it to set to true

Comment on lines +1553 to +1561
function FakePromise(fn) {
function resolve() { echo(`Test #${index} - resolve called`); throw new Error('oops'); }
function reject(e) { echo(`Test #${index} - reject called: ${e.message}`) }
fn(resolve, reject);
this.then = function(onResolve, onReject) {};
}

FakePromise.resolve = function() {};
Promise.any.call(FakePromise, []);
Copy link
Collaborator

Choose a reason for hiding this comment

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

This test case appears to be broken, or at least does not produce the result in the baseline.

@Kingwl
Copy link
Contributor Author

Kingwl commented Apr 21, 2020

Sorry for the delay too.
I'll take a look soon. Thanks for the review.

@rhuanjl
Copy link
Collaborator

rhuanjl commented Apr 21, 2020

Sorry for the delay too.
I'll take a look soon. Thanks for the review.

Great thanks.

Also, FYI, when you need to regenerate the bytecode headers again - I've recently enabled regenerating the bytecode on macOS or linux if you rebase on the latest master you'll find a script that can do this: https://github.com/microsoft/ChakraCore/blob/master/tools/xplatRegenByteCode.py

@rhuanjl
Copy link
Collaborator

rhuanjl commented Mar 14, 2021

@Kingwl are you likely to pick this up again? Would be good to get it finished

@Kingwl
Copy link
Contributor Author

Kingwl commented Mar 15, 2021

Sorry again. I almost(well, exactly) forgot about this issue.
I'd like to try to take this down.

BTW: I have join Microsoft. :XD

@rhuanjl
Copy link
Collaborator

rhuanjl commented Mar 15, 2021

It would be great to get this in if we can, though I note further to the points above:

  1. to solve the bytecode file conflicts you'll need to drop the changes you made to them then run the script tools/regenByteCode.py
  2. hopefully the JavascriptError.cpp and JavascriptPromise.cpp conflicts aren't too bad
  3. this is no longer maintained by microsoft so you'll need to sign our new contribution agreement (add signing it as another commit: https://github.com/chakra-core/ChakraCore/blob/master/ContributionAgreement.md)

@MadProbe
Copy link
Contributor

MadProbe commented Mar 15, 2021

@Kingwl, when you will work on this PR, please update AggregateError to complete implementation of Error cause proposal and resolve a TODO in error_cause.js test (Edit: Note that you must write separate tests for AggregateError because of errors parameter)

@Kingwl Kingwl mentioned this pull request Mar 16, 2021
@Kingwl Kingwl closed this Mar 16, 2021
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.

Implement Promise.any and AggregateError
4 participants