@@ -628,39 +628,34 @@ namespace Js
628
628
x = scriptContext->GetLibrary ()->GetUndefined ();
629
629
}
630
630
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);
648
632
}
649
633
650
634
JavascriptPromise* JavascriptPromise::InternalPromiseResolve (Var value, ScriptContext* scriptContext)
651
635
{
652
636
Var constructor = scriptContext->GetLibrary ()->GetPromiseConstructor ();
637
+ Var promise = PromiseResolve (constructor, value, scriptContext);
638
+ return UnsafeVarTo<JavascriptPromise>(promise);
639
+ }
653
640
641
+ Var JavascriptPromise::PromiseResolve (Var constructor, Var value, ScriptContext* scriptContext)
642
+ {
654
643
if (VarIs<JavascriptPromise>(value))
655
644
{
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
657
652
if (JavascriptConversion::SameValue (valueConstructor, constructor))
658
653
{
659
- return UnsafeVarTo<JavascriptPromise>( value) ;
654
+ return value;
660
655
}
661
656
}
662
657
663
- return UnsafeVarTo<JavascriptPromise>( CreateResolvedPromise (value, scriptContext, constructor) );
658
+ return CreateResolvedPromise (value, scriptContext, constructor);
664
659
}
665
660
666
661
// Promise.prototype.then as described in ES 2015 Section 25.4.5.3
@@ -1255,38 +1250,59 @@ namespace Js
1255
1250
return NewPromiseCapability (constructor, scriptContext);
1256
1251
});
1257
1252
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);
1260
1267
1261
1268
switch (sourcePromise->GetStatus ())
1262
1269
{
1263
1270
case PromiseStatusCode_Unresolved:
1264
1271
JavascriptPromiseReactionPair pair;
1265
1272
pair.resolveReaction = resolveReaction;
1266
1273
pair.rejectReaction = rejectReaction;
1267
-
1268
1274
sourcePromise->reactions ->Prepend (pair);
1269
1275
break ;
1276
+
1270
1277
case PromiseStatusCode_HasResolution:
1271
- EnqueuePromiseReactionTask (resolveReaction, CrossSite::MarshalVar (scriptContext, sourcePromise->result ), scriptContext);
1278
+ EnqueuePromiseReactionTask (
1279
+ resolveReaction,
1280
+ CrossSite::MarshalVar (scriptContext, sourcePromise->result ),
1281
+ scriptContext);
1272
1282
break ;
1283
+
1273
1284
case PromiseStatusCode_HasRejection:
1274
1285
{
1275
1286
if (!sourcePromise->GetIsHandled ())
1276
1287
{
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 );
1278
1292
}
1279
- EnqueuePromiseReactionTask (rejectReaction, CrossSite::MarshalVar (scriptContext, sourcePromise->result ), scriptContext);
1293
+ EnqueuePromiseReactionTask (
1294
+ rejectReaction,
1295
+ CrossSite::MarshalVar (scriptContext, sourcePromise->result ),
1296
+ scriptContext);
1280
1297
break ;
1281
1298
}
1299
+
1282
1300
default :
1283
1301
AssertMsg (false , " Promise status is in an invalid state" );
1284
1302
break ;
1285
1303
}
1286
1304
1287
1305
sourcePromise->SetIsHandled ();
1288
-
1289
- return promiseCapability->GetPromise ();
1290
1306
}
1291
1307
1292
1308
// Promise Resolve Thenable Job as described in ES 2015 Section 25.4.2.2
@@ -1601,7 +1617,11 @@ namespace Js
1601
1617
return undefinedVar;
1602
1618
}
1603
1619
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)
1605
1625
{
1606
1626
ScriptContext* scriptContext = gen->GetScriptContext ();
1607
1627
BEGIN_SAFE_REENTRANT_REGION (scriptContext->GetThreadContext ())
@@ -1610,13 +1630,16 @@ namespace Js
1610
1630
Var undefinedVar = library->GetUndefined ();
1611
1631
1612
1632
JavascriptExceptionObject* exception = nullptr ;
1613
- Var value = nullptr ;
1614
1633
RecyclableObject* next = nullptr ;
1615
- bool done;
1616
1634
1617
1635
try
1618
1636
{
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
+
1620
1643
next = VarTo<RecyclableObject>(nextVar);
1621
1644
}
1622
1645
catch (const JavascriptException& err)
@@ -1626,35 +1649,54 @@ namespace Js
1626
1649
1627
1650
if (exception != nullptr )
1628
1651
{
1629
- // finished with failure , reject the promise
1652
+ // If the generator threw an exception , reject the promise
1630
1653
TryRejectWithExceptionObject (exception, reject, scriptContext);
1631
1654
return ;
1632
1655
}
1633
1656
1634
1657
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))
1637
1662
{
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);
1640
1665
if (!JavascriptConversion::IsCallable (resolve))
1641
1666
{
1642
1667
JavascriptError::ThrowTypeError (scriptContext, JSERR_NeedFunction);
1643
1668
}
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);
1645
1676
1646
1677
return ;
1647
1678
}
1648
1679
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 );
1652
1695
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);
1658
1700
1659
1701
END_SAFE_REENTRANT_REGION
1660
1702
}
@@ -1798,6 +1840,12 @@ namespace Js
1798
1840
END_SAFE_REENTRANT_CALL
1799
1841
}
1800
1842
1843
+ JavascriptPromiseCapability* JavascriptPromise::UnusedPromiseCapability (ScriptContext* scriptContext)
1844
+ {
1845
+ // TODO(zenparsing): Optimize me
1846
+ return NewPromiseCapability (scriptContext->GetLibrary ()->GetPromiseConstructor (), scriptContext);
1847
+ }
1848
+
1801
1849
// CreatePromiseCapabilityRecord as described in ES6.0 (draft 29) Section 25.4.1.6.1
1802
1850
JavascriptPromiseCapability* JavascriptPromise::CreatePromiseCapabilityRecord (RecyclableObject* constructor, ScriptContext* scriptContext)
1803
1851
{
0 commit comments