This commit is contained in:
Cam Walter 2024-09-04 18:32:07 -05:00 коммит произвёл Greg Brail
Родитель 5c8707faa0
Коммит ffdf2313f1
6 изменённых файлов: 234 добавлений и 38 удалений

Просмотреть файл

@ -7,6 +7,8 @@
package org.mozilla.javascript;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* The class of error objects
@ -55,12 +57,7 @@ final class NativeError extends IdScriptableObject {
}
if (arglen >= 2) {
if (args[1] instanceof NativeObject) {
NativeObject options = (NativeObject) args[1];
Object cause = ScriptableObject.getProperty(options, "cause");
if (cause != NOT_FOUND) {
ScriptableObject.putProperty(obj, "cause", cause);
obj.setAttributes("cause", DONTENUM);
}
installCause((NativeObject) args[1], obj);
} else {
ScriptableObject.putProperty(obj, "fileName", ScriptRuntime.toString(args[1]));
if (arglen >= 3) {
@ -73,6 +70,58 @@ final class NativeError extends IdScriptableObject {
return obj;
}
static NativeError makeAggregate(
Context cx, Scriptable scope, IdFunctionObject ctorObj, Object[] args) {
Scriptable proto = (Scriptable) ctorObj.get("prototype", ctorObj);
NativeError obj = new NativeError();
obj.setPrototype(proto);
obj.setParentScope(scope);
int arglen = args.length;
if (arglen >= 1) {
if (arglen >= 2) {
if (!Undefined.isUndefined(args[1])) {
ScriptableObject.putProperty(obj, "message", ScriptRuntime.toString(args[1]));
obj.setAttributes("message", DONTENUM);
}
if (arglen >= 3) {
if (args[2] instanceof NativeObject) {
installCause((NativeObject) args[2], obj);
} else {
ScriptableObject.putProperty(
obj, "fileName", ScriptRuntime.toString(args[2]));
if (arglen >= 4) {
ScriptableObject.putProperty(
obj, "lineNumber", ScriptRuntime.toInt32(args[3]));
}
}
}
}
final Object iterator = ScriptRuntime.callIterator(args[0], cx, scope);
try (IteratorLikeIterable it = new IteratorLikeIterable(cx, scope, iterator)) {
List<Object> errors = new ArrayList<>();
for (Object o : it) {
errors.add(o);
}
Scriptable newArray = cx.newArray(scope, errors.toArray());
obj.defineProperty("errors", newArray, DONTENUM);
}
}
return obj;
}
static void installCause(NativeObject options, NativeError obj) {
Object cause = ScriptableObject.getProperty(options, "cause");
if (cause != NOT_FOUND) {
ScriptableObject.putProperty(obj, "cause", cause);
obj.setAttributes("cause", DONTENUM);
}
}
@Override
protected void fillConstructorProperties(IdFunctionObject ctor) {
addIdFunctionProperty(

Просмотреть файл

@ -113,8 +113,12 @@ public class NativeGlobal implements Serializable, IdFunctionCall {
cx, scope, TopLevel.Builtins.Error, ScriptRuntime.emptyArgs);
errorProto.defineProperty("name", name, DONTENUM);
errorProto.defineProperty("message", "", DONTENUM);
IdFunctionObject ctor =
new IdFunctionObject(obj, FTAG, Id_new_CommonError, name, 1, scope);
IdFunctionObject ctor;
if (error == TopLevel.NativeErrors.AggregateError) {
ctor = new IdFunctionObject(obj, FTAG, Id_new_AggregateError, name, 2, scope);
} else {
ctor = new IdFunctionObject(obj, FTAG, Id_new_CommonError, name, 1, scope);
}
ctor.markAsConstructor(errorProto);
ctor.setPrototype(nativeError);
errorProto.put("constructor", errorProto, ctor);
@ -203,6 +207,9 @@ public class NativeGlobal implements Serializable, IdFunctionCall {
// The implementation of all the ECMA error constructors
// (SyntaxError, TypeError, etc.)
return NativeError.make(cx, scope, f, args);
case Id_new_AggregateError:
return NativeError.makeAggregate(cx, scope, f, args);
}
}
throw f.unknown();
@ -760,5 +767,6 @@ public class NativeGlobal implements Serializable, IdFunctionCall {
Id_unescape = 12,
Id_uneval = 13,
LAST_SCOPE_FUNCTION_ID = 13,
Id_new_CommonError = 14;
Id_new_CommonError = 14,
Id_new_AggregateError = 15;
}

Просмотреть файл

@ -47,6 +47,8 @@ public class NativePromise extends ScriptableObject {
scope, "allSettled", 1, NativePromise::allSettled, DONTENUM, DONTENUM | READONLY);
constructor.defineConstructorMethod(
scope, "race", 1, NativePromise::race, DONTENUM, DONTENUM | READONLY);
constructor.defineConstructorMethod(
scope, "any", 1, NativePromise::any, DONTENUM, DONTENUM | READONLY);
ScriptRuntimeES6.addSymbolSpecies(cx, scope, constructor);
@ -280,6 +282,43 @@ public class NativePromise extends ScriptableObject {
}
}
private static Object any(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
Capability cap = new Capability(cx, scope, thisObj);
Object arg = (args.length > 0 ? args[0] : Undefined.instance);
IteratorLikeIterable iterable;
try {
Object maybeIterable = ScriptRuntime.callIterator(arg, cx, scope);
iterable = new IteratorLikeIterable(cx, scope, maybeIterable);
} catch (RhinoException re) {
cap.reject.call(
cx,
scope,
Undefined.SCRIPTABLE_UNDEFINED,
new Object[] {getErrorObject(cx, scope, re)});
return cap.promise;
}
IteratorLikeIterable.Itr iterator = iterable.iterator();
try {
PromiseAnyRejector rejector = new PromiseAnyRejector(iterator, thisObj, cap);
try {
return rejector.reject(cx, scope);
} finally {
if (!iterator.isDone()) {
iterable.close();
}
}
} catch (RhinoException re) {
cap.reject.call(
cx,
scope,
Undefined.SCRIPTABLE_UNDEFINED,
new Object[] {getErrorObject(cx, scope, re)});
return cap.promise;
}
}
// Promise.prototype.then
private Object then(
Context cx, Scriptable scope, LambdaConstructor defaultConstructor, Object[] args) {
@ -811,7 +850,109 @@ public class NativePromise extends ScriptableObject {
}
}
// This object keeps track of the state necessary to execute Promise.any
private static class PromiseAnyRejector {
// Limit the number of promises in Promise.any the same as it is in V8.
private static final int MAX_PROMISES = 1 << 21;
final ArrayList<Object> errors = new ArrayList<>();
int remainingElements = 1;
IteratorLikeIterable.Itr iterator;
Scriptable thisObj;
Capability capability;
PromiseAnyRejector(IteratorLikeIterable.Itr iter, Scriptable thisObj, Capability cap) {
this.iterator = iter;
this.thisObj = thisObj;
this.capability = cap;
}
Object reject(Context topCx, Scriptable topScope) {
int index = 0;
// Do this first because we should catch any exception before
// invoking the iterator.
Callable resolve =
ScriptRuntime.getPropFunctionAndThis(thisObj, "resolve", topCx, topScope);
Scriptable storedThis = ScriptRuntime.lastStoredScriptable(topCx);
// Iterate manually because we need to catch exceptions in a special way.
while (true) {
if (index == MAX_PROMISES) {
throw ScriptRuntime.rangeErrorById("msg.promise.any.toobig");
}
boolean hasNext;
Object nextVal = Undefined.instance;
boolean nextOk = false;
try {
hasNext = iterator.hasNext();
if (hasNext) {
nextVal = iterator.next();
}
nextOk = true;
} finally {
if (!nextOk) {
iterator.setDone(true);
}
}
if (!hasNext) {
if (--remainingElements == 0) {
Scriptable newArray = topCx.newArray(topScope, errors.toArray());
NativeError error =
(NativeError)
topCx.newObject(
topScope,
"AggregateError",
new Object[] {newArray});
throw new JavaScriptException(error, null, 0);
}
return capability.promise;
}
errors.add(Undefined.instance);
// Call "resolve" to get the next promise in the chain
Object nextPromise =
resolve.call(topCx, topScope, storedThis, new Object[] {nextVal});
// Create a resolution func that will stash its result in the right place
PromiseElementResolver eltResolver = new PromiseElementResolver(index);
LambdaFunction rejectFunc =
new LambdaFunction(
topScope,
1,
(Context cx,
Scriptable scope,
Scriptable thisObj,
Object[] args) -> {
Object value = (args.length > 0 ? args[0] : Undefined.instance);
return eltResolver.reject(cx, scope, value, this);
});
remainingElements++;
// Call "then" on the promise with the resolution func
Callable thenFunc =
ScriptRuntime.getPropFunctionAndThis(nextPromise, "then", topCx, topScope);
thenFunc.call(
topCx,
topScope,
ScriptRuntime.lastStoredScriptable(topCx),
new Object[] {capability.resolve, rejectFunc});
index++;
}
}
void finalRejection(Context cx, Scriptable scope) {
Scriptable newArray = cx.newArray(scope, errors.toArray());
NativeError error =
(NativeError) cx.newObject(scope, "AggregateError", new Object[] {newArray});
capability.reject.call(cx, scope, Undefined.SCRIPTABLE_UNDEFINED, new Object[] {error});
}
}
// This object keeps track of the state necessary to resolve one element in Promise.all
// and Promise.any
private static class PromiseElementResolver {
private boolean alreadyCalled = false;
@ -832,5 +973,17 @@ public class NativePromise extends ScriptableObject {
}
return Undefined.instance;
}
Object reject(Context cx, Scriptable scope, Object result, PromiseAnyRejector rejector) {
if (alreadyCalled) {
return Undefined.instance;
}
alreadyCalled = true;
rejector.errors.set(index, result);
if (--rejector.remainingElements == 0) {
rejector.finalRejection(cx, scope);
}
return Undefined.instance;
}
}
}

Просмотреть файл

@ -61,6 +61,8 @@ public class TopLevel extends IdScriptableObject {
/** An enumeration of built-in native errors. [ECMAScript 5 - 15.11.6] */
enum NativeErrors {
/** The AggregateError */
AggregateError,
/** Basic Error */
Error,
/** The native EvalError. */

Просмотреть файл

@ -967,5 +967,8 @@ msg.promise.capability.state =\
msg.promise.all.toobig =\
Too many inputs to Promise.all
msg.promise.any.toobig =\
Too many inputs to Promise.any
msg.typed.array.ctor.incompatible = \
Method %TypedArray%.prototype.{0} called on incompatible receiver

Просмотреть файл

@ -1050,9 +1050,14 @@ built-ins/Math 51/326 (15.64%)
built-ins/NaN 0/6 (0.0%)
built-ins/NativeErrors 43/117 (36.75%)
AggregateError/prototype 6/6 (100.0%)
AggregateError 19/19 (100.0%)
built-ins/NativeErrors 25/117 (21.37%)
AggregateError/errors-iterabletolist-failures.js
AggregateError/is-a-constructor.js {unsupported: [Reflect.construct]}
AggregateError/message-tostring-abrupt.js
AggregateError/message-tostring-abrupt-symbol.js
AggregateError/newtarget-proto-custom.js {unsupported: [Reflect.construct]}
AggregateError/newtarget-proto-fallback.js
AggregateError/proto-from-ctor-realm.js {unsupported: [Reflect]}
EvalError/prototype/not-error-object.js
EvalError/is-a-constructor.js {unsupported: [Reflect.construct]}
EvalError/proto-from-ctor-realm.js {unsupported: [Reflect]}
@ -1098,7 +1103,7 @@ built-ins/Number 24/335 (7.16%)
S9.3.1_A3_T1_U180E.js {unsupported: [u180e]}
S9.3.1_A3_T2_U180E.js {unsupported: [u180e]}
built-ins/Object 218/3403 (6.41%)
built-ins/Object 217/3403 (6.38%)
assign/assignment-to-readonly-property-of-target-must-throw-a-typeerror-exception.js
assign/not-a-constructor.js {unsupported: [Reflect.construct]}
assign/source-own-prop-desc-missing.js {unsupported: [Proxy]}
@ -1282,7 +1287,6 @@ built-ins/Object 218/3403 (6.41%)
seal/not-a-constructor.js {unsupported: [Reflect.construct]}
seal/proxy-no-ownkeys-returned-keys-order.js {unsupported: [Proxy, Reflect]}
seal/proxy-with-defineProperty-handler.js {unsupported: [Proxy, Reflect]}
seal/seal-aggregateerror.js
seal/seal-asyncarrowfunction.js
seal/seal-asyncfunction.js
seal/seal-asyncgeneratorfunction.js
@ -1304,7 +1308,7 @@ built-ins/Object 218/3403 (6.41%)
proto-from-ctor-realm.js {unsupported: [Reflect]}
subclass-object-arg.js {unsupported: [Reflect.construct, Reflect, class]}
built-ins/Promise 429/631 (67.99%)
built-ins/Promise 406/631 (64.34%)
allSettled/capability-resolve-throws-reject.js {unsupported: [async]}
allSettled/ctx-ctor.js {unsupported: [class]}
allSettled/does-not-invoke-array-setters.js {unsupported: [async]}
@ -1426,16 +1430,10 @@ built-ins/Promise 429/631 (67.99%)
all/S25.4.4.1_A8.1_T1.js {unsupported: [async]}
all/S25.4.4.1_A8.2_T1.js {unsupported: [async]}
all/S25.4.4.1_A8.2_T2.js {unsupported: [async]}
any/call-reject-element-after-return.js
any/call-reject-element-items.js
any/capability-executor-called-twice.js
any/capability-executor-not-callable.js
any/capability-reject-throws-no-close.js {unsupported: [async]}
any/capability-resolve-throws-no-close.js {unsupported: [async]}
any/capability-resolve-throws-reject.js {unsupported: [async]}
any/ctx-ctor.js {unsupported: [class]}
any/ctx-ctor-throws.js
any/ctx-non-ctor.js
any/invoke-resolve.js {unsupported: [async]}
any/invoke-resolve-error-close.js {unsupported: [async]}
any/invoke-resolve-error-reject.js {unsupported: [async]}
@ -1447,14 +1445,12 @@ built-ins/Promise 429/631 (67.99%)
any/invoke-resolve-on-promises-every-iteration-of-promise.js {unsupported: [async]}
any/invoke-resolve-on-values-every-iteration-of-custom.js {unsupported: [class, async]}
any/invoke-resolve-on-values-every-iteration-of-promise.js {unsupported: [async]}
any/invoke-resolve-return.js
any/invoke-then.js {unsupported: [async]}
any/invoke-then-error-close.js {unsupported: [async]}
any/invoke-then-error-reject.js {unsupported: [async]}
any/invoke-then-get-error-close.js {unsupported: [async]}
any/invoke-then-get-error-reject.js {unsupported: [async]}
any/invoke-then-on-promises-every-iteration.js {unsupported: [async]}
any/is-function.js
any/iter-arg-is-empty-iterable-reject.js {unsupported: [async]}
any/iter-arg-is-empty-string-reject.js {unsupported: [async]}
any/iter-arg-is-error-object-reject.js {unsupported: [async]}
@ -1484,28 +1480,15 @@ built-ins/Promise 429/631 (67.99%)
any/iter-returns-undefined-reject.js {unsupported: [async]}
any/iter-step-err-no-close.js {unsupported: [async]}
any/iter-step-err-reject.js {unsupported: [async]}
any/length.js
any/name.js
any/new-reject-function.js
any/not-a-constructor.js {unsupported: [Reflect.construct]}
any/prop-desc.js
any/reject-all-mixed.js {unsupported: [async]}
any/reject-deferred.js {unsupported: [async]}
any/reject-element-function-extensible.js
any/reject-element-function-length.js
any/reject-element-function-name.js
any/reject-element-function-nonconstructor.js
any/reject-element-function-property-order.js
any/reject-element-function-prototype.js
any/reject-from-same-thenable.js
any/reject-ignored-deferred.js {unsupported: [async]}
any/reject-ignored-immed.js {unsupported: [async]}
any/reject-immed.js {unsupported: [async]}
any/resolve-before-loop-exit.js
any/resolve-before-loop-exit-from-same.js
any/resolve-from-reject-catch.js {unsupported: [async]}
any/resolve-from-resolve-reject-catch.js {unsupported: [async]}
any/resolve-from-same-thenable.js
any/resolve-ignores-late-rejection.js {unsupported: [async]}
any/resolve-ignores-late-rejection-deferred.js {unsupported: [async]}
any/resolve-non-callable.js {unsupported: [async]}
@ -1515,8 +1498,6 @@ built-ins/Promise 429/631 (67.99%)
any/resolved-sequence-extra-ticks.js {unsupported: [async]}
any/resolved-sequence-mixed.js {unsupported: [async]}
any/resolved-sequence-with-rejections.js {unsupported: [async]}
any/returns-promise.js
any/species-get-error.js
prototype/catch/not-a-constructor.js {unsupported: [Reflect.construct]}
prototype/catch/S25.4.5.1_A3.1_T1.js {unsupported: [async]}
prototype/catch/S25.4.5.1_A3.1_T2.js {unsupported: [async]}