@@ -628,39 +628,34 @@ namespace Js
628628 x = scriptContext->GetLibrary ()->GetUndefined ();
629629 }
630630
631- // 3. If IsPromise(x) is true,
632- if (VarIs<JavascriptPromise>(x))
633- {
634- // a. Let xConstructor be Get(x, "constructor").
635- Var xConstructor = JavascriptOperators::GetProperty ((RecyclableObject*)x, PropertyIds::constructor, scriptContext);
636-
637- // b. If SameValue(xConstructor, C) is true, return x.
638- if (JavascriptConversion::SameValue (xConstructor, constructor))
639- {
640- return x;
641- }
642- }
643-
644- // 4. Let promiseCapability be NewPromiseCapability(C).
645- // 5. Perform ? Call(promiseCapability.[[Resolve]], undefined, << x >>).
646- // 6. Return promiseCapability.[[Promise]].
647- return CreateResolvedPromise (x, scriptContext, constructor);
631+ return PromiseResolve (constructor, x, scriptContext);
648632 }
649633
650634 JavascriptPromise* JavascriptPromise::InternalPromiseResolve (Var value, ScriptContext* scriptContext)
651635 {
652636 Var constructor = scriptContext->GetLibrary ()->GetPromiseConstructor ();
637+ Var promise = PromiseResolve (constructor, value, scriptContext);
638+ return UnsafeVarTo<JavascriptPromise>(promise);
639+ }
653640
641+ Var JavascriptPromise::PromiseResolve (Var constructor, Var value, ScriptContext* scriptContext)
642+ {
654643 if (VarIs<JavascriptPromise>(value))
655644 {
656- Var valueConstructor = JavascriptOperators::GetProperty ((RecyclableObject*)value, PropertyIds::constructor, scriptContext);
645+ Var valueConstructor = JavascriptOperators::GetProperty (
646+ (RecyclableObject*)value,
647+ PropertyIds::constructor,
648+ scriptContext);
649+
650+ // If `value` is a Promise or Promise subclass instance and its "constructor"
651+ // property is `constructor`, then return the value unchanged
657652 if (JavascriptConversion::SameValue (valueConstructor, constructor))
658653 {
659- return UnsafeVarTo<JavascriptPromise>( value) ;
654+ return value;
660655 }
661656 }
662657
663- return UnsafeVarTo<JavascriptPromise>( CreateResolvedPromise (value, scriptContext, constructor) );
658+ return CreateResolvedPromise (value, scriptContext, constructor);
664659 }
665660
666661 // Promise.prototype.then as described in ES 2015 Section 25.4.5.3
@@ -1255,38 +1250,59 @@ namespace Js
12551250 return NewPromiseCapability (constructor, scriptContext);
12561251 });
12571252
1258- JavascriptPromiseReaction* resolveReaction = JavascriptPromiseReaction::New (promiseCapability, fulfillmentHandler, scriptContext);
1259- JavascriptPromiseReaction* rejectReaction = JavascriptPromiseReaction::New (promiseCapability, rejectionHandler, scriptContext);
1253+ PerformPromiseThen (sourcePromise, promiseCapability, fulfillmentHandler, rejectionHandler, scriptContext);
1254+
1255+ return promiseCapability->GetPromise ();
1256+ }
1257+
1258+ void JavascriptPromise::PerformPromiseThen (
1259+ JavascriptPromise* sourcePromise,
1260+ JavascriptPromiseCapability* capability,
1261+ RecyclableObject* fulfillmentHandler,
1262+ RecyclableObject* rejectionHandler,
1263+ ScriptContext* scriptContext)
1264+ {
1265+ auto * resolveReaction = JavascriptPromiseReaction::New (capability, fulfillmentHandler, scriptContext);
1266+ auto * rejectReaction = JavascriptPromiseReaction::New (capability, rejectionHandler, scriptContext);
12601267
12611268 switch (sourcePromise->GetStatus ())
12621269 {
12631270 case PromiseStatusCode_Unresolved:
12641271 JavascriptPromiseReactionPair pair;
12651272 pair.resolveReaction = resolveReaction;
12661273 pair.rejectReaction = rejectReaction;
1267-
12681274 sourcePromise->reactions ->Prepend (pair);
12691275 break ;
1276+
12701277 case PromiseStatusCode_HasResolution:
1271- EnqueuePromiseReactionTask (resolveReaction, CrossSite::MarshalVar (scriptContext, sourcePromise->result ), scriptContext);
1278+ EnqueuePromiseReactionTask (
1279+ resolveReaction,
1280+ CrossSite::MarshalVar (scriptContext, sourcePromise->result ),
1281+ scriptContext);
12721282 break ;
1283+
12731284 case PromiseStatusCode_HasRejection:
12741285 {
12751286 if (!sourcePromise->GetIsHandled ())
12761287 {
1277- scriptContext->GetLibrary ()->CallNativeHostPromiseRejectionTracker (sourcePromise, CrossSite::MarshalVar (scriptContext, sourcePromise->result ), true );
1288+ scriptContext->GetLibrary ()->CallNativeHostPromiseRejectionTracker (
1289+ sourcePromise,
1290+ CrossSite::MarshalVar (scriptContext, sourcePromise->result ),
1291+ true );
12781292 }
1279- EnqueuePromiseReactionTask (rejectReaction, CrossSite::MarshalVar (scriptContext, sourcePromise->result ), scriptContext);
1293+ EnqueuePromiseReactionTask (
1294+ rejectReaction,
1295+ CrossSite::MarshalVar (scriptContext, sourcePromise->result ),
1296+ scriptContext);
12801297 break ;
12811298 }
1299+
12821300 default :
12831301 AssertMsg (false , " Promise status is in an invalid state" );
12841302 break ;
12851303 }
12861304
12871305 sourcePromise->SetIsHandled ();
1288-
1289- return promiseCapability->GetPromise ();
12901306 }
12911307
12921308 // Promise Resolve Thenable Job as described in ES 2015 Section 25.4.2.2
@@ -1601,7 +1617,11 @@ namespace Js
16011617 return undefinedVar;
16021618 }
16031619
1604- void JavascriptPromise::AsyncSpawnStep (JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction* nextFunction, JavascriptGenerator* gen, Var resolve, Var reject)
1620+ void JavascriptPromise::AsyncSpawnStep (
1621+ JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction* nextFunction,
1622+ JavascriptGenerator* gen,
1623+ Var resolve,
1624+ Var reject)
16051625 {
16061626 ScriptContext* scriptContext = gen->GetScriptContext ();
16071627 BEGIN_SAFE_REENTRANT_REGION (scriptContext->GetThreadContext ())
@@ -1610,13 +1630,16 @@ namespace Js
16101630 Var undefinedVar = library->GetUndefined ();
16111631
16121632 JavascriptExceptionObject* exception = nullptr ;
1613- Var value = nullptr ;
16141633 RecyclableObject* next = nullptr ;
1615- bool done;
16161634
16171635 try
16181636 {
1619- Var nextVar = CALL_FUNCTION (scriptContext->GetThreadContext (), nextFunction, CallInfo (CallFlags_Value, 1 ), undefinedVar);
1637+ Var nextVar = CALL_FUNCTION (
1638+ scriptContext->GetThreadContext (),
1639+ nextFunction,
1640+ CallInfo (CallFlags_Value, 1 ),
1641+ undefinedVar);
1642+
16201643 next = VarTo<RecyclableObject>(nextVar);
16211644 }
16221645 catch (const JavascriptException& err)
@@ -1626,35 +1649,54 @@ namespace Js
16261649
16271650 if (exception != nullptr )
16281651 {
1629- // finished with failure , reject the promise
1652+ // If the generator threw an exception , reject the promise
16301653 TryRejectWithExceptionObject (exception, reject, scriptContext);
16311654 return ;
16321655 }
16331656
16341657 Assert (next != nullptr );
1635- done = JavascriptConversion::ToBool (JavascriptOperators::GetProperty (next, PropertyIds::done, scriptContext), scriptContext);
1636- if (done)
1658+
1659+ Var done = JavascriptOperators::GetProperty (next, PropertyIds::done, scriptContext);
1660+
1661+ if (JavascriptConversion::ToBool (done, scriptContext))
16371662 {
1638- // finished with success , resolve the promise
1639- value = JavascriptOperators::GetProperty (next, PropertyIds::value, scriptContext);
1663+ // If the generator is done , resolve the promise
1664+ Var value = JavascriptOperators::GetProperty (next, PropertyIds::value, scriptContext);
16401665 if (!JavascriptConversion::IsCallable (resolve))
16411666 {
16421667 JavascriptError::ThrowTypeError (scriptContext, JSERR_NeedFunction);
16431668 }
1644- CALL_FUNCTION (scriptContext->GetThreadContext (), VarTo<RecyclableObject>(resolve), CallInfo (CallFlags_Value, 2 ), undefinedVar, value);
1669+
1670+ CALL_FUNCTION (
1671+ scriptContext->GetThreadContext (),
1672+ VarTo<RecyclableObject>(resolve),
1673+ CallInfo (CallFlags_Value, 2 ),
1674+ undefinedVar,
1675+ value);
16451676
16461677 return ;
16471678 }
16481679
1649- // not finished, chain off the yielded promise and `step` again
1650- JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction* successFunction = library->CreatePromiseAsyncSpawnStepArgumentExecutorFunction (EntryJavascriptPromiseAsyncSpawnCallStepExecutorFunction, gen, undefinedVar, resolve, reject);
1651- JavascriptPromiseAsyncSpawnStepArgumentExecutorFunction* failFunction = library->CreatePromiseAsyncSpawnStepArgumentExecutorFunction (EntryJavascriptPromiseAsyncSpawnCallStepExecutorFunction, gen, undefinedVar, resolve, reject, true );
1680+ // Chain off the yielded promise and step again
1681+ auto * successFunction = library->CreatePromiseAsyncSpawnStepArgumentExecutorFunction (
1682+ EntryJavascriptPromiseAsyncSpawnCallStepExecutorFunction,
1683+ gen,
1684+ undefinedVar,
1685+ resolve,
1686+ reject);
1687+
1688+ auto * failFunction = library->CreatePromiseAsyncSpawnStepArgumentExecutorFunction (
1689+ EntryJavascriptPromiseAsyncSpawnCallStepExecutorFunction,
1690+ gen,
1691+ undefinedVar,
1692+ resolve,
1693+ reject,
1694+ true );
16521695
1653- JavascriptFunction* promiseResolve = library->EnsurePromiseResolveFunction ();
1654- value = JavascriptOperators::GetProperty (next, PropertyIds::value, scriptContext);
1655- Var promiseVar = CALL_FUNCTION (scriptContext->GetThreadContext (), promiseResolve, CallInfo (CallFlags_Value, 2 ), library->GetPromiseConstructor (), value);
1656- JavascriptPromise* promise = VarTo<JavascriptPromise>(promiseVar);
1657- CreateThenPromise (promise, successFunction, failFunction, scriptContext);
1696+ Var value = JavascriptOperators::GetProperty (next, PropertyIds::value, scriptContext);
1697+ JavascriptPromise* promise = InternalPromiseResolve (value, scriptContext);
1698+ JavascriptPromiseCapability* unused = UnusedPromiseCapability (scriptContext);
1699+ PerformPromiseThen (promise, unused, successFunction, failFunction, scriptContext);
16581700
16591701 END_SAFE_REENTRANT_REGION
16601702 }
@@ -1798,6 +1840,12 @@ namespace Js
17981840 END_SAFE_REENTRANT_CALL
17991841 }
18001842
1843+ JavascriptPromiseCapability* JavascriptPromise::UnusedPromiseCapability (ScriptContext* scriptContext)
1844+ {
1845+ // TODO(zenparsing): Optimize me
1846+ return NewPromiseCapability (scriptContext->GetLibrary ()->GetPromiseConstructor (), scriptContext);
1847+ }
1848+
18011849 // CreatePromiseCapabilityRecord as described in ES6.0 (draft 29) Section 25.4.1.6.1
18021850 JavascriptPromiseCapability* JavascriptPromise::CreatePromiseCapabilityRecord (RecyclableObject* constructor, ScriptContext* scriptContext)
18031851 {
0 commit comments