From e57684a4243cbee22dbf90f7753d253ef3dca613 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 4 Jun 2024 08:52:03 +0200 Subject: [PATCH 001/265] Delegate execute to executeDouble. --- .../oracle/truffle/js/nodes/cast/JSToDoubleNode.java | 6 ++++-- .../nodes/cast/JSToIntegerWithoutRoundingNode.java | 12 ++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/cast/JSToDoubleNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/cast/JSToDoubleNode.java index 2c22ad7a84e..fc6abc6226f 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/cast/JSToDoubleNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/cast/JSToDoubleNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -62,7 +62,9 @@ @GenerateUncached public abstract class JSToDoubleNode extends JavaScriptBaseNode { - public abstract Object execute(Object value); + public final double execute(Object value) { + return executeDouble(value); + } public abstract double executeDouble(Object value); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/cast/JSToIntegerWithoutRoundingNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/cast/JSToIntegerWithoutRoundingNode.java index 43ee3660f28..7ace789265f 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/cast/JSToIntegerWithoutRoundingNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/cast/JSToIntegerWithoutRoundingNode.java @@ -60,12 +60,12 @@ @ImportStatic(JSGuards.class) public abstract class JSToIntegerWithoutRoundingNode extends JavaScriptBaseNode { - public abstract Object execute(Object value); - - public final double executeDouble(Object value) { - return (double) execute(value); + public final double execute(Object value) { + return executeDouble(value); } + public abstract double executeDouble(Object value); + @Specialization protected static double doInteger(int value) { return value; @@ -110,12 +110,12 @@ protected static double doUndefined(@SuppressWarnings("unused") Object value) { } @Specialization - protected final long doSymbol(@SuppressWarnings("unused") Symbol value) { + protected final double doSymbol(@SuppressWarnings("unused") Symbol value) { throw Errors.createTypeErrorCannotConvertToNumber("a Symbol value", this); } @Specialization - protected final long doBigInt(@SuppressWarnings("unused") BigInt value) { + protected final double doBigInt(@SuppressWarnings("unused") BigInt value) { throw Errors.createTypeErrorCannotConvertToNumber("a BigInt value", this); } From 5329984992fc48c4621b1a1243a5a2bd0280eb07 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 4 Jun 2024 08:54:13 +0200 Subject: [PATCH 002/265] Apply TruffleBoundary to various TemporalUtil methods and replace isValidTimeZoneName with null check. --- .../js/builtins/ConstructorBuiltins.java | 4 +-- ...mporalBalanceDateDurationRelativeNode.java | 36 ++++++++++++------- .../ToRelativeTemporalObjectNode.java | 4 +-- .../ToTemporalTimeZoneSlotValueNode.java | 5 +-- .../temporal/ToTemporalZonedDateTimeNode.java | 4 +-- .../builtins/intl/JSDateTimeFormat.java | 1 + .../truffle/js/runtime/util/TemporalUtil.java | 30 +++++++++------- 7 files changed, 52 insertions(+), 32 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java index 280f38284bc..de8ee81b634 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java @@ -1442,10 +1442,10 @@ private JSDynamicObject constructTemporalTimeZoneIntl(JSDynamicObject newTarget, TruffleString id = idParam; boolean canParse = TemporalUtil.canParseAsTimeZoneNumericUTCOffset(id); if (!canParse) { - if (!TemporalUtil.isValidTimeZoneName(id)) { + id = TemporalUtil.canonicalizeTimeZoneName(id); + if (id == null) { throw TemporalErrors.createRangeErrorInvalidTimeZoneString(); } - id = TemporalUtil.canonicalizeTimeZoneName(id); } JSRealm realm = getRealm(); JSDynamicObject proto = getPrototype(realm, newTarget); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalBalanceDateDurationRelativeNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalBalanceDateDurationRelativeNode.java index 6f09422acb1..66b240fb26d 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalBalanceDateDurationRelativeNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalBalanceDateDurationRelativeNode.java @@ -47,6 +47,7 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; +import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.nodes.JavaScriptBaseNode; import com.oracle.truffle.js.nodes.access.CreateDataPropertyNode; import com.oracle.truffle.js.nodes.function.JSFunctionCallNode; @@ -57,6 +58,7 @@ import com.oracle.truffle.js.runtime.builtins.JSOrdinary; import com.oracle.truffle.js.runtime.builtins.temporal.CalendarMethodsRecord; import com.oracle.truffle.js.runtime.builtins.temporal.DateDurationRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalCalendar; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDuration; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationObject; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateObject; @@ -132,14 +134,14 @@ private DateDurationRecord getUnitYear(double years, double months, double weeks assert days == 0 : days; var yearsMonthsDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, years, months, 0, 0, 0, 0, 0, 0, 0, 0, this, errorBranch); - var later = calendarDateAdd(calendarRec, plainRelativeTo, yearsMonthsDuration, node, errorBranch); - var untilResult = calendarDateUntil(calendarRec, plainRelativeTo, later, untilOptions); + var later = calendarDateAdd(calendarRec, plainRelativeTo, yearsMonthsDuration, node, errorBranch, ctx, realm); + var untilResult = calendarDateUntil(calendarRec, plainRelativeTo, later, untilOptions, ctx, realm); return new DateDurationRecord(untilResult.getYears(), untilResult.getMonths(), weeks, days); } else { var yearsMonthsWeeksDaysDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, years, months, weeks, days, 0, 0, 0, 0, 0, 0, this, errorBranch); - var later = calendarDateAdd(calendarRec, plainRelativeTo, yearsMonthsWeeksDaysDuration, node, errorBranch); - var untilResult = calendarDateUntil(calendarRec, plainRelativeTo, later, untilOptions); + var later = calendarDateAdd(calendarRec, plainRelativeTo, yearsMonthsWeeksDaysDuration, node, errorBranch, ctx, realm); + var untilResult = calendarDateUntil(calendarRec, plainRelativeTo, later, untilOptions, ctx, realm); return new DateDurationRecord(untilResult.getYears(), untilResult.getMonths(), untilResult.getWeeks(), untilResult.getDays()); } } @@ -154,8 +156,8 @@ private DateDurationRecord getUnitMonth(double years, double months, double week } else { var monthsWeeksDaysDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, years, months, weeks, days, 0, 0, 0, 0, 0, 0, this, errorBranch); - var later = calendarDateAdd(calendarRec, plainRelativeTo, monthsWeeksDaysDuration, node, errorBranch); - var untilResult = calendarDateUntil(calendarRec, plainRelativeTo, later, untilOptions); + var later = calendarDateAdd(calendarRec, plainRelativeTo, monthsWeeksDaysDuration, node, errorBranch, ctx, realm); + var untilResult = calendarDateUntil(calendarRec, plainRelativeTo, later, untilOptions, ctx, realm); return new DateDurationRecord(years, untilResult.getMonths(), untilResult.getWeeks(), untilResult.getDays()); } } @@ -167,30 +169,40 @@ private DateDurationRecord getUnitWeek(double years, double months, double weeks assert months == 0 : months; var weeksDaysDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, years, months, weeks, days, 0, 0, 0, 0, 0, 0, this, errorBranch); - var later = calendarDateAdd(calendarRec, plainRelativeTo, weeksDaysDuration, node, errorBranch); - var untilResult = calendarDateUntil(calendarRec, plainRelativeTo, later, untilOptions); + var later = calendarDateAdd(calendarRec, plainRelativeTo, weeksDaysDuration, node, errorBranch, ctx, realm); + var untilResult = calendarDateUntil(calendarRec, plainRelativeTo, later, untilOptions, ctx, realm); return new DateDurationRecord(years, months, untilResult.getWeeks(), untilResult.getDays()); } protected JSTemporalPlainDateObject calendarDateAdd(CalendarMethodsRecord calendarRec, JSTemporalPlainDateObject plainDate, JSTemporalDurationObject duration, - Node node, InlinedBranchProfile errorBranch) { + Node node, InlinedBranchProfile errorBranch, JSContext ctx, JSRealm realm) { if (callDateAddNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); callDateAddNode = insert(JSFunctionCallNode.createCall()); } - Object calendar = TemporalUtil.toCalendarObject(calendarRec.receiver()); + Object calendar = toCalendarObject(calendarRec.receiver(), ctx, realm); Object addedDate = callDateAddNode.executeCall(JSArguments.create(calendar, calendarRec.dateAdd(), plainDate, duration)); return TemporalUtil.requireTemporalDate(addedDate, node, errorBranch); } - protected JSTemporalDurationObject calendarDateUntil(CalendarMethodsRecord calendarRec, JSTemporalPlainDateObject one, JSTemporalPlainDateObject two, JSDynamicObject options) { + protected JSTemporalDurationObject calendarDateUntil(CalendarMethodsRecord calendarRec, JSTemporalPlainDateObject one, JSTemporalPlainDateObject two, JSDynamicObject options, + JSContext ctx, JSRealm realm) { if (callDateUntilNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); callDateUntilNode = insert(JSFunctionCallNode.createCall()); } - Object calendar = TemporalUtil.toCalendarObject(calendarRec.receiver()); + Object calendar = toCalendarObject(calendarRec.receiver(), ctx, realm); Object addedDate = callDateUntilNode.executeCall(JSArguments.create(calendar, calendarRec.dateUntil(), one, two, options)); return TemporalUtil.requireTemporalDuration(addedDate); } + private static Object toCalendarObject(Object calendarSlotValue, JSContext ctx, JSRealm realm) { + Object calendar; + if (calendarSlotValue instanceof TruffleString calendarID) { + calendar = JSTemporalCalendar.create(ctx, realm, calendarID); + } else { + calendar = calendarSlotValue; + } + return calendar; + } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToRelativeTemporalObjectNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToRelativeTemporalObjectNode.java index d0201160282..992f4a23cce 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToRelativeTemporalObjectNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToRelativeTemporalObjectNode.java @@ -191,11 +191,11 @@ protected Result toRelativeTemporalObject(JSDynamicObject options, if (timeZoneName != null) { // If ParseText(! StringToCodePoints(timeZoneName), TimeZoneNumericUTCOffset) // is not a List of errors - if (!TemporalUtil.isValidTimeZoneName(timeZoneName)) { + timeZoneName = TemporalUtil.canonicalizeTimeZoneName(timeZoneName); + if (timeZoneName == null) { errorBranch.enter(this); throw TemporalErrors.createRangeErrorInvalidTimeZoneString(); } - timeZoneName = TemporalUtil.canonicalizeTimeZoneName(timeZoneName); timeZone = TemporalUtil.createTemporalTimeZone(ctx, realm, timeZoneName); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalTimeZoneSlotValueNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalTimeZoneSlotValueNode.java index 8aba87cd8e5..22ca01c6026 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalTimeZoneSlotValueNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalTimeZoneSlotValueNode.java @@ -91,11 +91,12 @@ protected Object toTemporalTimeZoneSlotValue(Object temporalTimeZoneLike, if (offsetMinutes != null && name == null) { return TemporalUtil.formatTimeZoneOffsetString(TemporalUtil.parseTimeZoneOffsetString(offsetMinutes)); } - if (!TemporalUtil.isValidTimeZoneName(name)) { + TruffleString timeZoneName = TemporalUtil.canonicalizeTimeZoneName(name); + if (timeZoneName == null) { errorBranch.enter(this); throw TemporalErrors.createRangeErrorInvalidTimeZoneString(); } - return TemporalUtil.canonicalizeTimeZoneName(name); + return timeZoneName; } else { errorBranch.enter(this); throw Errors.createTypeErrorNotAString(temporalTimeZoneLike); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalZonedDateTimeNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalZonedDateTimeNode.java index f487ed8d7f9..80674716273 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalZonedDateTimeNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalZonedDateTimeNode.java @@ -143,11 +143,11 @@ public JSTemporalZonedDateTimeObject toTemporalZonedDateTime(Object item, JSDyna TruffleString timeZoneName = resultZDT.getTimeZoneResult().getName(); assert timeZoneName != null; if (!TemporalUtil.canParseAsTimeZoneNumericUTCOffset(timeZoneName)) { - if (!TemporalUtil.isValidTimeZoneName(timeZoneName)) { + timeZoneName = TemporalUtil.canonicalizeTimeZoneName(timeZoneName); + if (timeZoneName == null) { errorBranch.enter(this); throw TemporalErrors.createRangeErrorInvalidTimeZoneString(); } - timeZoneName = TemporalUtil.canonicalizeTimeZoneName(timeZoneName); } offsetString = resultZDT.getTimeZoneResult().getOffsetString(); if (resultZDT.getTimeZoneResult().isZ()) { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/intl/JSDateTimeFormat.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/intl/JSDateTimeFormat.java index 08a886a76ab..861e1205685 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/intl/JSDateTimeFormat.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/intl/JSDateTimeFormat.java @@ -670,6 +670,7 @@ public static String canonicalizeTimeZoneName(String tzId) { } } + @TruffleBoundary public static String canonicalizeTimeZoneName(TruffleString tzId) { return canonicalizeTimeZoneName(Strings.toJavaString(tzId)); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java index 0d16ff7f55a..81ddf678e9d 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java @@ -1280,13 +1280,10 @@ public static JSTemporalTimeZoneObject createTemporalTimeZone(JSContext ctx, JSR return JSTemporalTimeZone.create(ctx, realm, proto, offsetNs, newIdentifier); } + @TruffleBoundary public static TruffleString canonicalizeTimeZoneName(TruffleString timeZone) { - assert isValidTimeZoneName(timeZone); - return Strings.fromJavaString(JSDateTimeFormat.canonicalizeTimeZoneName(timeZone)); - } - - public static boolean isValidTimeZoneName(TruffleString timeZone) { - return JSDateTimeFormat.canonicalizeTimeZoneName(timeZone) != null; + String tzId = JSDateTimeFormat.canonicalizeTimeZoneName(timeZone); + return tzId == null ? null : Strings.fromJavaString(tzId); } @TruffleBoundary @@ -1299,6 +1296,7 @@ public static double getDouble(JSDynamicObject ob, TruffleString key, double def return n.longValue(); } + @TruffleBoundary public static boolean isoDateTimeWithinLimits(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond, int nanosecond) { if (-isoTimeBoundYears <= year && year <= isoTimeBoundYears) { // fastpath check @@ -1422,6 +1420,7 @@ public static JSTemporalDurationRecord constrainTime(int hours, int minutes, int constrainToRange(nanoseconds, 0, 999)); } + @TruffleBoundary public static JSTemporalDateTimeRecord toTemporalTimeRecord(JSDynamicObject temporalTimeLike) { boolean any = false; @@ -1462,6 +1461,7 @@ public static JSTemporalDateTimeRecord toTemporalTimeRecord(JSDynamicObject temp return JSTemporalDateTimeRecord.create(0, 0, 0, hour, minute, second, millisecond, microsecond, nanosecond); } + @TruffleBoundary public static Number toIntegerThrowOnInfinity(Object value) { Number integer = toIntegerOrInfinity(value); if (Double.isInfinite(JSRuntime.doubleValue(integer))) { @@ -1470,6 +1470,7 @@ public static Number toIntegerThrowOnInfinity(Object value) { return integer; } + @TruffleBoundary public static double toIntegerWithoutRounding(Object argument) { Number number = JSRuntime.toNumber(argument); double dNumber = JSRuntime.doubleValue(number); @@ -1495,10 +1496,12 @@ public static Number toIntegerOrInfinity(Object value) { return JSRuntime.truncateDouble(d); } + @TruffleBoundary public static JSTemporalPlainDateObject calendarDateAdd(CalendarMethodsRecord calendarRec, JSDynamicObject date, JSDynamicObject duration) { return calendarDateAdd(calendarRec, date, duration, Undefined.instance); } + @TruffleBoundary public static JSTemporalPlainDateObject calendarDateAdd(CalendarMethodsRecord calendarRec, JSDynamicObject date, JSDynamicObject duration, JSDynamicObject options) { Object dateAddPrepared = calendarRec.dateAdd(); Object calendar = toCalendarObject(calendarRec.receiver()); @@ -1506,6 +1509,7 @@ public static JSTemporalPlainDateObject calendarDateAdd(CalendarMethodsRecord ca return requireTemporalDate(addedDate); } + @TruffleBoundary public static JSTemporalDurationObject calendarDateUntil(CalendarMethodsRecord calendarRec, JSDynamicObject one, JSDynamicObject two, JSDynamicObject options) { Object dateUntilPrepared = calendarRec.dateUntil(); Object calendar = toCalendarObject(calendarRec.receiver()); @@ -2374,6 +2378,7 @@ public static Unit defaultTemporalLargestUnit(double years, double months, doubl return Unit.NANOSECOND; } + @TruffleBoundary public static JSDynamicObject toPartialDuration(Object temporalDurationLike, JSContext ctx, IsObjectNode isObjectNode, JSToIntegerWithoutRoundingNode toInt, Node node, InlinedBranchProfile errorBranch) { if (!isObjectNode.executeBoolean(temporalDurationLike)) { @@ -2579,7 +2584,7 @@ public static TimeDurationRecord differenceTime(int h1, int min1, int s1, int ms bt.millisecond() * sign, bt.microsecond() * sign, bt.nanosecond() * sign); } - // 4.5.15 + @TruffleBoundary public static TimeRecord roundTime(int hours, int minutes, int seconds, int milliseconds, int microseconds, int nanoseconds, double increment, Unit unit, RoundingMode roundingMode, Long dayLengthNsParam) { double fractionalSecond = ((double) nanoseconds / 1_000_000_000) + ((double) microseconds / 1_000_000) + @@ -2731,6 +2736,7 @@ public static TimeRecord addTimeDouble(int hour, int minute, int second, int mil microsecond + microseconds, nanosecond + nanoseconds, node, errorBranch); } + @TruffleBoundary public static JSTemporalDurationRecord roundISODateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond, int nanosecond, double increment, Unit unit, RoundingMode roundingMode, Long dayLength) { TimeRecord rt = roundTime(hour, minute, second, millisecond, microsecond, nanosecond, increment, unit, roundingMode, dayLength); @@ -2995,6 +3001,7 @@ public static TimeZoneMethodsRecord createTimeZoneMethodsRecordOnlyGetOffsetNano return new TimeZoneMethodsRecord(timeZone, getOffsetNanosecondsForMethod, null); } + @TruffleBoundary public static TruffleString builtinTimeZoneGetOffsetStringFor(JSContext context, JSRealm realm, TimeZoneMethodsRecord timeZoneRec, JSDynamicObject instant) { long offsetNanoseconds = getOffsetNanosecondsFor(context, realm, timeZoneRec, instant); return formatTimeZoneOffsetString(offsetNanoseconds); @@ -3568,11 +3575,7 @@ public static OptionalLong getIANATimeZonePreviousTransition(BigInt nanoseconds, @TruffleBoundary public static boolean canParseAsTimeZoneNumericUTCOffset(TruffleString string) { try { - JSTemporalParserRecord rec = (new TemporalParser(string)).parseTimeZoneNumericUTCOffset(); - if (rec == null) { - return false; // it cannot be parsed - } - return true; + return new TemporalParser(string).parseTimeZoneNumericUTCOffset() != null; } catch (Exception ex) { return false; } @@ -3644,6 +3647,7 @@ public static Object calendarInLeapYear(TemporalCalendarGetterNode getterNode, O } // 12.1.38 + @TruffleBoundary public static void isoResolveMonth(JSContext ctx, JSDynamicObject fields, JSToIntegerOrInfinityNode toIntegerOrInfinity) { Object month = JSObject.get(fields, MONTH); Object monthCode = JSObject.get(fields, MONTH_CODE); @@ -3683,6 +3687,7 @@ public static ISODateRecord isoDateFromFields(JSDynamicObject fields, Overflow o dtoi(JSRuntime.doubleValue(day)), overflow); } + @TruffleBoundary public static ISODateRecord isoYearMonthFromFields(JSDynamicObject fields, Overflow overflow) { Number year = (Number) JSObject.get(fields, YEAR); Number month = (Number) JSObject.get(fields, MONTH); @@ -3691,6 +3696,7 @@ public static ISODateRecord isoYearMonthFromFields(JSDynamicObject fields, Overf return new ISODateRecord(result.year(), result.month(), 1); } + @TruffleBoundary public static ISODateRecord isoMonthDayFromFields(JSDynamicObject fields, Overflow overflow) { Number month = (Number) JSObject.get(fields, MONTH); Number day = (Number) JSObject.get(fields, DAY); From 75b9520c9412f414e3a3873f777fd51bb279ca71 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 4 Jun 2024 08:56:35 +0200 Subject: [PATCH 003/265] Separate toTemporalRoundingIncrement into GetRoundingIncrementOptionNode and validateTemporalRoundingIncrement. --- .../TemporalDurationPrototypeBuiltins.java | 9 +- .../TemporalInstantPrototypeBuiltins.java | 9 +- ...emporalPlainDateTimePrototypeBuiltins.java | 25 +++++- .../TemporalPlainTimePrototypeBuiltins.java | 12 +-- ...emporalZonedDateTimePrototypeBuiltins.java | 25 +++++- .../GetRoundingIncrementOptionNode.java | 77 +++++++++++++++++ .../truffle/js/runtime/util/TemporalUtil.java | 82 ++----------------- 7 files changed, 144 insertions(+), 95 deletions(-) create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/GetRoundingIncrementOptionNode.java diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java index e35290adaba..c0d9cb81b3e 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java @@ -78,10 +78,10 @@ import com.oracle.truffle.js.builtins.temporal.TemporalDurationPrototypeBuiltinsFactory.JSTemporalDurationWithNodeGen; import com.oracle.truffle.js.nodes.cast.JSNumberToBigIntNode; import com.oracle.truffle.js.nodes.cast.JSToIntegerWithoutRoundingNode; -import com.oracle.truffle.js.nodes.cast.JSToNumberNode; import com.oracle.truffle.js.nodes.function.JSBuiltin; import com.oracle.truffle.js.nodes.function.JSBuiltinNode; import com.oracle.truffle.js.nodes.temporal.CalendarMethodsRecordLookupNode; +import com.oracle.truffle.js.nodes.temporal.GetRoundingIncrementOptionNode; import com.oracle.truffle.js.nodes.temporal.GetTemporalUnitNode; import com.oracle.truffle.js.nodes.temporal.TemporalBalanceDateDurationRelativeNode; import com.oracle.truffle.js.nodes.temporal.TemporalDurationAddNode; @@ -406,7 +406,6 @@ protected JSTemporalDurationRound(JSContext context, JSBuiltin builtin) { @Specialization protected JSTemporalDurationObject round(JSTemporalDurationObject duration, Object roundToParam, @Bind("this") Node node, - @Cached JSToNumberNode toNumber, @Cached TruffleString.EqualNode equalNode, @Cached TemporalDurationAddNode durationAddNode, @Cached InlinedConditionProfile roundToIsTString, @@ -420,6 +419,7 @@ protected JSTemporalDurationObject round(JSTemporalDurationObject duration, Obje @Cached TemporalGetOptionNode getOptionNode, @Cached GetTemporalUnitNode getLargestUnit, @Cached GetTemporalUnitNode getSmallestUnit, + @Cached GetRoundingIncrementOptionNode getRoundingIncrementOption, @Cached InlinedBranchProfile errorBranch, @Cached InlinedConditionProfile optionUndefined) { if (roundToParam == Undefined.instance) { @@ -456,10 +456,13 @@ protected JSTemporalDurationObject round(JSTemporalDurationObject duration, Obje throw Errors.createRangeError("at least one of smallestUnit or largestUnit is required"); } JSRealm realm = getRealm(); + double roundingIncrement = getRoundingIncrementOption.execute(roundTo); TemporalUtil.validateTemporalUnitRange(largestUnit, smallestUnit); RoundingMode roundingMode = toTemporalRoundingMode(roundTo, HALF_EXPAND, equalNode, getOptionNode); Double maximum = TemporalUtil.maximumTemporalDurationRoundingIncrement(smallestUnit); - double roundingIncrement = TemporalUtil.toTemporalRoundingIncrement(roundTo, maximum, false, toNumber); + if (maximum != null) { + TemporalUtil.validateTemporalRoundingIncrement(roundingIncrement, maximum, false, node, errorBranch); + } var relativeToRec = toRelativeTemporalObjectNode.execute(roundTo); JSTemporalZonedDateTimeObject zonedRelativeTo = relativeToRec.zonedRelativeTo(); JSTemporalPlainDateObject plainRelativeTo = relativeToRec.plainRelativeTo(); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalInstantPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalInstantPrototypeBuiltins.java index cdfe730ba1c..5f3cbc97d4b 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalInstantPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalInstantPrototypeBuiltins.java @@ -66,10 +66,10 @@ import com.oracle.truffle.js.builtins.temporal.TemporalInstantPrototypeBuiltinsFactory.JSTemporalInstantToZonedDateTimeNodeGen; import com.oracle.truffle.js.builtins.temporal.TemporalInstantPrototypeBuiltinsFactory.JSTemporalInstantUntilSinceNodeGen; import com.oracle.truffle.js.nodes.access.PropertyGetNode; -import com.oracle.truffle.js.nodes.cast.JSToNumberNode; import com.oracle.truffle.js.nodes.function.JSBuiltin; import com.oracle.truffle.js.nodes.function.JSBuiltinNode; import com.oracle.truffle.js.nodes.temporal.GetDifferenceSettingsNode; +import com.oracle.truffle.js.nodes.temporal.GetRoundingIncrementOptionNode; import com.oracle.truffle.js.nodes.temporal.GetTemporalUnitNode; import com.oracle.truffle.js.nodes.temporal.SnapshotOwnPropertiesNode; import com.oracle.truffle.js.nodes.temporal.TemporalGetOptionNode; @@ -297,10 +297,10 @@ protected JSTemporalInstantRound(JSContext context, JSBuiltin builtin) { @Specialization protected JSTemporalInstantObject round(JSTemporalInstantObject instant, Object roundToParam, - @Cached JSToNumberNode toNumber, @Cached TruffleString.EqualNode equalNode, @Cached TemporalGetOptionNode getOptionNode, @Cached GetTemporalUnitNode getSmallestUnit, + @Cached GetRoundingIncrementOptionNode getRoundingIncrementOption, @Cached InlinedBranchProfile errorBranch, @Cached InlinedConditionProfile optionUndefined) { if (roundToParam == Undefined.instance) { @@ -314,8 +314,9 @@ protected JSTemporalInstantObject round(JSTemporalInstantObject instant, Object } else { roundTo = getOptionsObject(roundToParam, this, errorBranch, optionUndefined); } - Unit smallestUnit = getSmallestUnit.execute(roundTo, TemporalConstants.SMALLEST_UNIT, TemporalUtil.unitMappingTime, Unit.REQUIRED); + double roundingIncrement = getRoundingIncrementOption.execute(roundTo); RoundingMode roundingMode = toTemporalRoundingMode(roundTo, HALF_EXPAND, equalNode, getOptionNode); + Unit smallestUnit = getSmallestUnit.execute(roundTo, TemporalConstants.SMALLEST_UNIT, TemporalUtil.unitMappingTime, Unit.REQUIRED); double maximum; if (Unit.HOUR == smallestUnit) { maximum = TemporalUtil.HOURS_PER_DAY; @@ -331,7 +332,7 @@ protected JSTemporalInstantObject round(JSTemporalInstantObject instant, Object assert Unit.NANOSECOND == smallestUnit; maximum = TemporalUtil.NS_PER_DAY; } - double roundingIncrement = TemporalUtil.toTemporalRoundingIncrement(roundTo, maximum, true, toNumber); + TemporalUtil.validateTemporalRoundingIncrement(roundingIncrement, maximum, true, this, errorBranch); BigInt roundedNs = TemporalUtil.roundTemporalInstant(instant.getNanoseconds(), (long) roundingIncrement, smallestUnit, roundingMode); return JSTemporalInstant.create(getContext(), getRealm(), roundedNs); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainDateTimePrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainDateTimePrototypeBuiltins.java index 7a0fdb30e20..7837115505e 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainDateTimePrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainDateTimePrototypeBuiltins.java @@ -80,12 +80,12 @@ import com.oracle.truffle.js.builtins.temporal.TemporalPlainDateTimePrototypeBuiltinsFactory.JSTemporalPlainDateTimeWithPlainTimeNodeGen; import com.oracle.truffle.js.nodes.access.CreateDataPropertyNode; import com.oracle.truffle.js.nodes.access.EnumerableOwnPropertyNamesNode; -import com.oracle.truffle.js.nodes.cast.JSToNumberNode; import com.oracle.truffle.js.nodes.function.JSBuiltin; import com.oracle.truffle.js.nodes.function.JSBuiltinNode; import com.oracle.truffle.js.nodes.temporal.CalendarMethodsRecordLookupNode; import com.oracle.truffle.js.nodes.temporal.CreateTimeZoneMethodsRecordNode; import com.oracle.truffle.js.nodes.temporal.GetDifferenceSettingsNode; +import com.oracle.truffle.js.nodes.temporal.GetRoundingIncrementOptionNode; import com.oracle.truffle.js.nodes.temporal.GetTemporalUnitNode; import com.oracle.truffle.js.nodes.temporal.IsPartialTemporalObjectNode; import com.oracle.truffle.js.nodes.temporal.SnapshotOwnPropertiesNode; @@ -724,10 +724,10 @@ protected JSTemporalPlainDateTimeRoundNode(JSContext context, JSBuiltin builtin) @Specialization final JSTemporalPlainDateTimeObject round(JSTemporalPlainDateTimeObject dt, Object roundToParam, - @Cached JSToNumberNode toNumberNode, @Cached TruffleString.EqualNode equalNode, @Cached TemporalGetOptionNode getOptionNode, @Cached GetTemporalUnitNode getSmallestUnit, + @Cached GetRoundingIncrementOptionNode getRoundingIncrementOption, @Cached InlinedBranchProfile errorBranch, @Cached InlinedConditionProfile optionUndefined) { if (roundToParam == Undefined.instance) { @@ -740,9 +740,26 @@ final JSTemporalPlainDateTimeObject round(JSTemporalPlainDateTimeObject dt, Obje } else { roundTo = getOptionsObject(roundToParam, this, errorBranch, optionUndefined); } - Unit smallestUnit = getSmallestUnit.execute(roundTo, TemporalConstants.SMALLEST_UNIT, TemporalUtil.unitMappingTimeOrDay, Unit.REQUIRED); + double roundingIncrement = getRoundingIncrementOption.execute(roundTo); RoundingMode roundingMode = toTemporalRoundingMode(roundTo, HALF_EXPAND, equalNode, getOptionNode); - double roundingIncrement = TemporalUtil.toTemporalDateTimeRoundingIncrement(roundTo, smallestUnit, toNumberNode); + Unit smallestUnit = getSmallestUnit.execute(roundTo, TemporalConstants.SMALLEST_UNIT, TemporalUtil.unitMappingTimeOrDay, Unit.REQUIRED); + double maximum; + boolean inclusive; + if (Unit.DAY == smallestUnit) { + maximum = 1; + inclusive = true; + } else { + if (Unit.HOUR == smallestUnit) { + maximum = 24; + } else if (Unit.MINUTE == smallestUnit || Unit.SECOND == smallestUnit) { + maximum = 60; + } else { + assert Unit.MILLISECOND == smallestUnit || Unit.MICROSECOND == smallestUnit || Unit.NANOSECOND == smallestUnit; + maximum = 1000; + } + inclusive = false; + } + TemporalUtil.validateTemporalRoundingIncrement(roundingIncrement, maximum, inclusive, this, errorBranch); JSTemporalDurationRecord result = TemporalUtil.roundISODateTime(dt.getYear(), dt.getMonth(), dt.getDay(), dt.getHour(), dt.getMinute(), dt.getSecond(), dt.getMillisecond(), dt.getMicrosecond(), dt.getNanosecond(), roundingIncrement, smallestUnit, roundingMode, null); return JSTemporalPlainDateTime.create(getContext(), getRealm(), diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainTimePrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainTimePrototypeBuiltins.java index 8ff83d0616f..a4b889aeb5a 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainTimePrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainTimePrototypeBuiltins.java @@ -71,11 +71,11 @@ import com.oracle.truffle.js.builtins.temporal.TemporalPlainTimePrototypeBuiltinsFactory.JSTemporalPlainTimeWithNodeGen; import com.oracle.truffle.js.nodes.cast.JSToIntegerAsIntNode; import com.oracle.truffle.js.nodes.cast.JSToIntegerThrowOnInfinityNode; -import com.oracle.truffle.js.nodes.cast.JSToNumberNode; import com.oracle.truffle.js.nodes.function.JSBuiltin; import com.oracle.truffle.js.nodes.function.JSBuiltinNode; import com.oracle.truffle.js.nodes.temporal.CreateTimeZoneMethodsRecordNode; import com.oracle.truffle.js.nodes.temporal.GetDifferenceSettingsNode; +import com.oracle.truffle.js.nodes.temporal.GetRoundingIncrementOptionNode; import com.oracle.truffle.js.nodes.temporal.GetTemporalUnitNode; import com.oracle.truffle.js.nodes.temporal.IsPartialTemporalObjectNode; import com.oracle.truffle.js.nodes.temporal.SnapshotOwnPropertiesNode; @@ -412,10 +412,10 @@ protected JSTemporalPlainTimeRound(JSContext context, JSBuiltin builtin) { @Specialization protected JSTemporalPlainTimeObject round(JSTemporalPlainTimeObject temporalTime, Object roundToParam, - @Cached JSToNumberNode toNumber, @Cached TruffleString.EqualNode equalNode, @Cached TemporalGetOptionNode getOptionNode, @Cached GetTemporalUnitNode getSmallestUnit, + @Cached GetRoundingIncrementOptionNode getRoundingIncrementOption, @Cached InlinedBranchProfile errorBranch, @Cached InlinedConditionProfile optionUndefined) { if (roundToParam == Undefined.instance) { @@ -429,9 +429,10 @@ protected JSTemporalPlainTimeObject round(JSTemporalPlainTimeObject temporalTime } else { roundTo = getOptionsObject(roundToParam, this, errorBranch, optionUndefined); } - Unit smallestUnit = getSmallestUnit.execute(roundTo, TemporalConstants.SMALLEST_UNIT, TemporalUtil.unitMappingTime, Unit.REQUIRED); + double roundingIncrement = getRoundingIncrementOption.execute(roundTo); RoundingMode roundingMode = toTemporalRoundingMode(roundTo, HALF_EXPAND, equalNode, getOptionNode); - int maximum; + Unit smallestUnit = getSmallestUnit.execute(roundTo, TemporalConstants.SMALLEST_UNIT, TemporalUtil.unitMappingTime, Unit.REQUIRED); + double maximum; if (smallestUnit == Unit.HOUR) { maximum = 24; } else if (smallestUnit == Unit.MINUTE || smallestUnit == Unit.SECOND) { @@ -439,8 +440,7 @@ protected JSTemporalPlainTimeObject round(JSTemporalPlainTimeObject temporalTime } else { maximum = 1000; } - double roundingIncrement = TemporalUtil.toTemporalRoundingIncrement(roundTo, (double) maximum, - false, toNumber); + TemporalUtil.validateTemporalRoundingIncrement(roundingIncrement, maximum, false, this, errorBranch); TimeRecord result = TemporalUtil.roundTime(temporalTime.getHour(), temporalTime.getMinute(), temporalTime.getSecond(), temporalTime.getMillisecond(), temporalTime.getMicrosecond(), temporalTime.getNanosecond(), roundingIncrement, smallestUnit, roundingMode, null); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalZonedDateTimePrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalZonedDateTimePrototypeBuiltins.java index 685102e7040..26ec66855b3 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalZonedDateTimePrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalZonedDateTimePrototypeBuiltins.java @@ -86,12 +86,12 @@ import com.oracle.truffle.js.nodes.access.CreateDataPropertyNode; import com.oracle.truffle.js.nodes.access.EnumerableOwnPropertyNamesNode; import com.oracle.truffle.js.nodes.cast.JSNumberToBigIntNode; -import com.oracle.truffle.js.nodes.cast.JSToNumberNode; import com.oracle.truffle.js.nodes.function.JSBuiltin; import com.oracle.truffle.js.nodes.function.JSBuiltinNode; import com.oracle.truffle.js.nodes.temporal.CalendarMethodsRecordLookupNode; import com.oracle.truffle.js.nodes.temporal.CreateTimeZoneMethodsRecordNode; import com.oracle.truffle.js.nodes.temporal.GetDifferenceSettingsNode; +import com.oracle.truffle.js.nodes.temporal.GetRoundingIncrementOptionNode; import com.oracle.truffle.js.nodes.temporal.GetTemporalUnitNode; import com.oracle.truffle.js.nodes.temporal.IsPartialTemporalObjectNode; import com.oracle.truffle.js.nodes.temporal.SnapshotOwnPropertiesNode; @@ -919,10 +919,10 @@ protected JSTemporalZonedDateTimeRound(JSContext context, JSBuiltin builtin) { @Specialization protected JSDynamicObject round(JSTemporalZonedDateTimeObject zonedDateTime, Object roundToParam, - @Cached JSToNumberNode toNumber, @Cached TruffleString.EqualNode equalNode, @Cached TemporalGetOptionNode getOptionNode, @Cached GetTemporalUnitNode getSmallestUnit, + @Cached GetRoundingIncrementOptionNode getRoundingIncrementOption, @Cached InlinedBranchProfile errorBranch, @Cached InlinedConditionProfile optionUndefined, @Cached CreateTimeZoneMethodsRecordNode createTimeZoneMethodsRecord) { @@ -937,9 +937,26 @@ protected JSDynamicObject round(JSTemporalZonedDateTimeObject zonedDateTime, Obj } else { roundTo = getOptionsObject(roundToParam, this, errorBranch, optionUndefined); } - Unit smallestUnit = getSmallestUnit.execute(roundTo, TemporalConstants.SMALLEST_UNIT, TemporalUtil.unitMappingTimeOrDay, Unit.REQUIRED); + double roundingIncrement = getRoundingIncrementOption.execute(roundTo); RoundingMode roundingMode = toTemporalRoundingMode(roundTo, HALF_EXPAND, equalNode, getOptionNode); - double roundingIncrement = TemporalUtil.toTemporalDateTimeRoundingIncrement(roundTo, smallestUnit, toNumber); + Unit smallestUnit = getSmallestUnit.execute(roundTo, TemporalConstants.SMALLEST_UNIT, TemporalUtil.unitMappingTimeOrDay, Unit.REQUIRED); + double maximum; + boolean inclusive; + if (Unit.DAY == smallestUnit) { + maximum = 1; + inclusive = true; + } else { + if (Unit.HOUR == smallestUnit) { + maximum = 24; + } else if (Unit.MINUTE == smallestUnit || Unit.SECOND == smallestUnit) { + maximum = 60; + } else { + assert Unit.MILLISECOND == smallestUnit || Unit.MICROSECOND == smallestUnit || Unit.NANOSECOND == smallestUnit; + maximum = 1000; + } + inclusive = false; + } + TemporalUtil.validateTemporalRoundingIncrement(roundingIncrement, maximum, inclusive, this, errorBranch); Object timeZone = zonedDateTime.getTimeZone(); var timeZoneRec = createTimeZoneMethodsRecord.executeFull(timeZone); JSRealm realm = getRealm(); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/GetRoundingIncrementOptionNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/GetRoundingIncrementOptionNode.java new file mode 100644 index 00000000000..84fd5fce6d2 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/GetRoundingIncrementOptionNode.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.nodes.temporal; + +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.ImportStatic; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.profiles.InlinedBranchProfile; +import com.oracle.truffle.js.nodes.JavaScriptBaseNode; +import com.oracle.truffle.js.nodes.access.PropertyGetNode; +import com.oracle.truffle.js.nodes.cast.JSToDoubleNode; +import com.oracle.truffle.js.runtime.Errors; +import com.oracle.truffle.js.runtime.objects.Undefined; +import com.oracle.truffle.js.runtime.util.TemporalConstants; + +@ImportStatic(TemporalConstants.class) +public abstract class GetRoundingIncrementOptionNode extends JavaScriptBaseNode { + + public abstract double execute(Object options); + + @Specialization + protected final double toTemporalRoundingIncrement(Object options, + @Cached("create(ROUNDING_INCREMENT, getJSContext())") PropertyGetNode getRoundingIncrement, + @Cached JSToDoubleNode toDouble, + @Cached InlinedBranchProfile errorBranch) { + Object value = getRoundingIncrement.getValue(options); + if (value == Undefined.instance) { + return 1; + } + double doubleValue = toDouble.executeDouble(value); + double increment = Math.floor(doubleValue); + if (!Double.isFinite(doubleValue) || increment < 1 || increment > 1e9) { + errorBranch.enter(this); + throw Errors.createRangeError("Increment out of range."); + } + return increment; + } + +} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java index 81ddf678e9d..46eb466fa29 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java @@ -81,7 +81,6 @@ import static com.oracle.truffle.js.runtime.util.TemporalConstants.OVERFLOW; import static com.oracle.truffle.js.runtime.util.TemporalConstants.PREFER; import static com.oracle.truffle.js.runtime.util.TemporalConstants.REJECT; -import static com.oracle.truffle.js.runtime.util.TemporalConstants.ROUNDING_INCREMENT; import static com.oracle.truffle.js.runtime.util.TemporalConstants.SECOND; import static com.oracle.truffle.js.runtime.util.TemporalConstants.SECONDS; import static com.oracle.truffle.js.runtime.util.TemporalConstants.TIME_ZONE; @@ -128,8 +127,6 @@ import com.oracle.truffle.js.nodes.cast.JSToIntegerOrInfinityNode; import com.oracle.truffle.js.nodes.cast.JSToIntegerThrowOnInfinityNode; import com.oracle.truffle.js.nodes.cast.JSToIntegerWithoutRoundingNode; -import com.oracle.truffle.js.nodes.cast.JSToNumberNode; -import com.oracle.truffle.js.nodes.cast.JSToStringNode; import com.oracle.truffle.js.nodes.temporal.CalendarMethodsRecordLookupNode; import com.oracle.truffle.js.nodes.temporal.TemporalCalendarDateFromFieldsNode; import com.oracle.truffle.js.nodes.temporal.TemporalCalendarGetterNode; @@ -479,65 +476,17 @@ private static Map createUnitMapping(List si return Map.copyOf(map); } - // 13.3 - public static double defaultNumberOptions(Object value, double minimum, double maximum, double fallback, - JSToNumberNode toNumber) { - if (value == Undefined.instance) { - return fallback; - } - double numberValue = JSRuntime.doubleValue(toNumber.executeNumber(value)); - if (Double.isNaN(numberValue) || numberValue < minimum || numberValue > maximum || (Double.isInfinite(numberValue) && Double.isInfinite(maximum))) { - throw Errors.createRangeError("Numeric value out of range."); - } - return Math.floor(numberValue); - } - - // 13.4 - public static double getNumberOption(Object options, TruffleString property, double minimum, double maximum, double fallback, - JSToNumberNode numberNode) { - Object value = JSRuntime.get(options, property); - return defaultNumberOptions(value, minimum, maximum, fallback, numberNode); - } - - // 13.5 - public static Object getStringOrNumberOption(JSDynamicObject options, TruffleString property, List stringValues, - double minimum, double maximum, Object fallback, JSToStringNode toStringNode, TemporalGetOptionNode getOptionNode) { - assert JSRuntime.isObject(options); - Object value = getOptionNode.execute(options, property, OptionType.NUMBER_AND_STRING, null, fallback); - if (value instanceof Number) { - double numberValue = JSRuntime.doubleValue((Number) value); - if (Double.isNaN(numberValue) || numberValue < minimum || numberValue > maximum) { - throw Errors.createRangeError("Numeric value out of range."); - } - return Math.floor(numberValue); - } - value = toStringNode.executeString(value); - if (stringValues != null && !Boundaries.listContainsUnchecked(stringValues, value)) { - throw Errors.createRangeError("Given string value is not in string values"); - } - return value; - } - - // 13.17 - public static double toTemporalRoundingIncrement(Object options, Double dividend, boolean inclusive, - JSToNumberNode toNumber) { + public static double validateTemporalRoundingIncrement(double increment, double dividend, boolean inclusive, + Node node, InlinedBranchProfile errorBranch) { double maximum; - double dDividend = Double.NaN; - if (dividend == null) { - maximum = Double.POSITIVE_INFINITY; + if (inclusive) { + maximum = dividend; } else { - dDividend = JSRuntime.doubleValue(dividend); - if (inclusive) { - maximum = dDividend; - } else if (dDividend > 1) { - maximum = dDividend - 1; - } else { - maximum = 1; - } + assert dividend > 1 : dividend; + maximum = dividend - 1; } - - double increment = getNumberOption(options, ROUNDING_INCREMENT, 1, maximum, 1, toNumber); - if (dividend != null && dDividend % increment != 0) { + if (increment > maximum || dividend % increment != 0) { + errorBranch.enter(node); throw Errors.createRangeError("Increment out of range."); } return increment; @@ -2745,21 +2694,6 @@ public static JSTemporalDurationRecord roundISODateTime(int year, int month, int rt.hour(), rt.minute(), rt.second(), rt.millisecond(), rt.microsecond(), rt.nanosecond()); } - public static double toTemporalDateTimeRoundingIncrement(JSDynamicObject options, Unit smallestUnit, JSToNumberNode toNumber) { - int maximum = 0; - if (Unit.DAY == smallestUnit) { - maximum = 1; - } else if (Unit.HOUR == smallestUnit) { - maximum = 24; - } else if (Unit.MINUTE == smallestUnit || Unit.SECOND == smallestUnit) { - maximum = 60; - } else { - assert Unit.MILLISECOND == smallestUnit || Unit.MICROSECOND == smallestUnit || Unit.NANOSECOND == smallestUnit; - maximum = 1000; - } - return toTemporalRoundingIncrement(options, (double) maximum, false, toNumber); - } - public static boolean isValidTime(int hours, int minutes, int seconds, int milliseconds, int microseconds, int nanoseconds) { if (hours < 0 || hours > 23) { return false; From b3419b47d4fac63fc784e1ac59a40af3065fc23a Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 4 Jun 2024 09:09:40 +0200 Subject: [PATCH 004/265] Skip rounding for smallestUnit == "nanosecond" and roundingIncrement == 1. --- .../TemporalPlainDateTimePrototypeBuiltins.java | 6 ++++++ .../TemporalZonedDateTimePrototypeBuiltins.java | 10 +++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainDateTimePrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainDateTimePrototypeBuiltins.java index 7837115505e..270dc75a143 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainDateTimePrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainDateTimePrototypeBuiltins.java @@ -760,6 +760,12 @@ final JSTemporalPlainDateTimeObject round(JSTemporalPlainDateTimeObject dt, Obje inclusive = false; } TemporalUtil.validateTemporalRoundingIncrement(roundingIncrement, maximum, inclusive, this, errorBranch); + if (smallestUnit == Unit.NANOSECOND && roundingIncrement == 1) { + return JSTemporalPlainDateTime.create(getContext(), getRealm(), + dt.getYear(), dt.getMonth(), dt.getDay(), + dt.getHour(), dt.getMinute(), dt.getSecond(), + dt.getMillisecond(), dt.getMicrosecond(), dt.getNanosecond(), dt.getCalendar(), this, errorBranch); + } JSTemporalDurationRecord result = TemporalUtil.roundISODateTime(dt.getYear(), dt.getMonth(), dt.getDay(), dt.getHour(), dt.getMinute(), dt.getSecond(), dt.getMillisecond(), dt.getMicrosecond(), dt.getNanosecond(), roundingIncrement, smallestUnit, roundingMode, null); return JSTemporalPlainDateTime.create(getContext(), getRealm(), diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalZonedDateTimePrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalZonedDateTimePrototypeBuiltins.java index 26ec66855b3..1eddc6659e7 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalZonedDateTimePrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalZonedDateTimePrototypeBuiltins.java @@ -957,11 +957,15 @@ protected JSDynamicObject round(JSTemporalZonedDateTimeObject zonedDateTime, Obj inclusive = false; } TemporalUtil.validateTemporalRoundingIncrement(roundingIncrement, maximum, inclusive, this, errorBranch); - Object timeZone = zonedDateTime.getTimeZone(); - var timeZoneRec = createTimeZoneMethodsRecord.executeFull(timeZone); JSRealm realm = getRealm(); - JSTemporalInstantObject instant = JSTemporalInstant.create(getContext(), realm, zonedDateTime.getNanoseconds()); + BigInt thisNs = zonedDateTime.getNanoseconds(); + Object timeZone = zonedDateTime.getTimeZone(); Object calendar = zonedDateTime.getCalendar(); + if (smallestUnit == Unit.NANOSECOND && roundingIncrement == 1) { + return JSTemporalZonedDateTime.create(getContext(), realm, thisNs, timeZone, calendar); + } + var timeZoneRec = createTimeZoneMethodsRecord.executeFull(timeZone); + JSTemporalInstantObject instant = JSTemporalInstant.create(getContext(), realm, thisNs); long offsetNanoseconds = TemporalUtil.getOffsetNanosecondsFor(getContext(), realm, timeZoneRec, instant); JSTemporalPlainDateTimeObject tdt = TemporalUtil.builtinTimeZoneGetPlainDateTimeFor(getContext(), realm, instant, calendar, offsetNanoseconds); Object isoCalendar = TemporalUtil.getISO8601Calendar(getContext(), realm); From 2923ef764c91b4701ef75247c755214fdfbcad94 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 4 Jun 2024 09:17:29 +0200 Subject: [PATCH 005/265] Update test262 status. --- graal-js/test/test262.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/graal-js/test/test262.json b/graal-js/test/test262.json index 444f90d2f07..402e4f714cc 100644 --- a/graal-js/test/test262.json +++ b/graal-js/test/test262.json @@ -1990,10 +1990,6 @@ "filePath" : "built-ins/Temporal/Duration/prototype/round/round-negative-result.js", "status" : "FAIL", "comment" : "Temporal failures" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/roundingincrement-out-of-range.js", - "status" : "FAIL", - "comment" : "new failures 2023-02-13" }, { "filePath" : "built-ins/Temporal/Duration/prototype/round/roundingmode-ceil.js", "status" : "FAIL", From 317e22eabc6d82aebabc5287606ad384e5347019 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 4 Jun 2024 09:29:35 +0200 Subject: [PATCH 006/265] Fix order of operations in Temporal.Duration.prototype.round. --- .../TemporalDurationPrototypeBuiltins.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java index c0d9cb81b3e..24b2a4f8bcd 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java @@ -434,6 +434,13 @@ protected JSTemporalDurationObject round(JSTemporalDurationObject duration, Obje } boolean smallestUnitPresent = true; boolean largestUnitPresent = true; + Unit largestUnit = getLargestUnit.execute(roundTo, TemporalConstants.LARGEST_UNIT, TemporalUtil.unitMappingDateTimeOrAuto, Unit.EMPTY); + var relativeToRec = toRelativeTemporalObjectNode.execute(roundTo); + JSTemporalZonedDateTimeObject zonedRelativeTo = relativeToRec.zonedRelativeTo(); + JSTemporalPlainDateObject plainRelativeTo = relativeToRec.plainRelativeTo(); + TimeZoneMethodsRecord timeZoneRec = relativeToRec.timeZoneRec(); + double roundingIncrement = getRoundingIncrementOption.execute(roundTo); + RoundingMode roundingMode = toTemporalRoundingMode(roundTo, HALF_EXPAND, equalNode, getOptionNode); Unit smallestUnit = getSmallestUnit.execute(roundTo, TemporalConstants.SMALLEST_UNIT, TemporalUtil.unitMappingDateTime, Unit.EMPTY); if (smallestUnit == Unit.EMPTY) { smallestUnitPresent = false; @@ -444,7 +451,6 @@ protected JSTemporalDurationObject round(JSTemporalDurationObject duration, Obje duration.getMinutes(), duration.getSeconds(), duration.getMilliseconds(), duration.getMicroseconds()); Unit defaultLargestUnit = TemporalUtil.largerOfTwoTemporalUnits(existingLargestUnit, smallestUnit); - Unit largestUnit = getLargestUnit.execute(roundTo, TemporalConstants.LARGEST_UNIT, TemporalUtil.unitMappingDateTimeOrAuto, Unit.EMPTY); if (largestUnit == Unit.EMPTY) { largestUnitPresent = false; largestUnit = defaultLargestUnit; @@ -456,17 +462,11 @@ protected JSTemporalDurationObject round(JSTemporalDurationObject duration, Obje throw Errors.createRangeError("at least one of smallestUnit or largestUnit is required"); } JSRealm realm = getRealm(); - double roundingIncrement = getRoundingIncrementOption.execute(roundTo); TemporalUtil.validateTemporalUnitRange(largestUnit, smallestUnit); - RoundingMode roundingMode = toTemporalRoundingMode(roundTo, HALF_EXPAND, equalNode, getOptionNode); Double maximum = TemporalUtil.maximumTemporalDurationRoundingIncrement(smallestUnit); if (maximum != null) { TemporalUtil.validateTemporalRoundingIncrement(roundingIncrement, maximum, false, node, errorBranch); } - var relativeToRec = toRelativeTemporalObjectNode.execute(roundTo); - JSTemporalZonedDateTimeObject zonedRelativeTo = relativeToRec.zonedRelativeTo(); - JSTemporalPlainDateObject plainRelativeTo = relativeToRec.plainRelativeTo(); - TimeZoneMethodsRecord timeZoneRec = relativeToRec.timeZoneRec(); boolean roundingGranularityIsNoop = smallestUnit == Unit.NANOSECOND && roundingIncrement == 1; boolean calendarUnitsPresent = duration.getYears() != 0 || duration.getMonths() != 0 || duration.getWeeks() != 0; From 3d353501a14512c93137b1b2775bec8b2252ef75 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 4 Jun 2024 09:34:51 +0200 Subject: [PATCH 007/265] Use GetRoundingIncrementOptionNode in GetDifferenceSettingsNode, too. --- .../temporal/GetDifferenceSettingsNode.java | 33 ++----------------- 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/GetDifferenceSettingsNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/GetDifferenceSettingsNode.java index 41c708f068e..2f3ff8b5078 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/GetDifferenceSettingsNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/GetDifferenceSettingsNode.java @@ -48,12 +48,9 @@ import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.builtins.temporal.JSTemporalBuiltinOperation; import com.oracle.truffle.js.nodes.JavaScriptBaseNode; -import com.oracle.truffle.js.runtime.Errors; -import com.oracle.truffle.js.runtime.JSRuntime; import com.oracle.truffle.js.runtime.objects.JSDynamicObject; import com.oracle.truffle.js.runtime.util.TemporalConstants; import com.oracle.truffle.js.runtime.util.TemporalUtil; -import com.oracle.truffle.js.runtime.util.TemporalUtil.OptionType; import com.oracle.truffle.js.runtime.util.TemporalUtil.RoundingMode; import com.oracle.truffle.js.runtime.util.TemporalUtil.Unit; @@ -85,11 +82,11 @@ final GetDifferenceSettingsResult getDifferenceSettings(int operation, JSDynamic @Cached TemporalGetOptionNode getOptionNode, @Cached TruffleString.EqualNode equalNode, @Cached GetTemporalUnitNode getLargestUnit, - @Cached TemporalGetOptionNode getRoundingIncrement, + @Cached GetRoundingIncrementOptionNode getRoundingIncrementOption, @Cached GetTemporalUnitNode getSmallestUnit) { assert unitMappingOrAuto.containsKey(TemporalConstants.AUTO) && !unitMapping.containsKey(TemporalConstants.AUTO); Unit largestUnit = getLargestUnit.execute(resolvedOptions, TemporalConstants.LARGEST_UNIT, unitMappingOrAuto, Unit.AUTO); - double roundingIncrement = toTemporalRoundingIncrement(resolvedOptions, getRoundingIncrement, errorBranch); + double roundingIncrement = getRoundingIncrementOption.execute(resolvedOptions); RoundingMode roundingMode = JSTemporalBuiltinOperation.toTemporalRoundingMode(resolvedOptions, TemporalConstants.TRUNC, equalNode, getOptionNode); if (operation == TemporalUtil.SINCE) { roundingMode = TemporalUtil.negateTemporalRoundingMode(roundingMode); @@ -102,32 +99,8 @@ final GetDifferenceSettingsResult getDifferenceSettings(int operation, JSDynamic TemporalUtil.validateTemporalUnitRange(largestUnit, smallestUnit); Double maximum = TemporalUtil.maximumTemporalDurationRoundingIncrement(smallestUnit); if (maximum != null) { - validateTemporalRoundingIncrement(roundingIncrement, maximum, false, errorBranch); + TemporalUtil.validateTemporalRoundingIncrement(roundingIncrement, maximum, false, this, errorBranch); } return new GetDifferenceSettingsResult(smallestUnit, largestUnit, roundingMode, (long) roundingIncrement); } - - private double toTemporalRoundingIncrement(JSDynamicObject resolvedOptions, TemporalGetOptionNode getRoundingIncrement, InlinedBranchProfile errorBranch) { - double increment = JSRuntime.doubleValue((Number) getRoundingIncrement.execute(resolvedOptions, TemporalConstants.ROUNDING_INCREMENT, OptionType.NUMBER, null, 1.0)); - double integerIncrement = JSRuntime.truncateDouble(increment); - if (!Double.isFinite(increment) || integerIncrement < 1 || integerIncrement > 1e9) { - errorBranch.enter(this); - throw Errors.createRangeError("Numeric value out of range."); - } - return integerIncrement; - } - - private void validateTemporalRoundingIncrement(double increment, double dividend, boolean inclusive, InlinedBranchProfile errorBranch) { - double maximum; - if (inclusive) { - maximum = dividend; - } else { - assert dividend > 1 : dividend; - maximum = dividend - 1; - } - if (increment > maximum || dividend % increment != 0) { - errorBranch.enter(this); - throw Errors.createRangeError("Increment out of range."); - } - } } From 0048bb5cd71f6cc684f10382c8e3c4023bb173d4 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 4 Jun 2024 11:17:31 +0200 Subject: [PATCH 008/265] Implement and use ToTemporal[Partial]DurationRecord. --- .../TemporalDurationPrototypeBuiltins.java | 33 +---- .../temporal/ToTemporalDurationNode.java | 25 +--- .../ToTemporalDurationRecordNode.java | 93 +++++++++++++ .../ToTemporalPartialDurationRecordNode.java | 122 ++++++++++++++++++ .../builtins/temporal/JSTemporalDuration.java | 75 ----------- .../temporal/JSTemporalDurationRecord.java | 3 + .../truffle/js/runtime/util/TemporalUtil.java | 29 ----- 7 files changed, 228 insertions(+), 152 deletions(-) create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalDurationRecordNode.java create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalPartialDurationRecordNode.java diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java index 24b2a4f8bcd..39defa8cfdb 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java @@ -41,21 +41,10 @@ package com.oracle.truffle.js.builtins.temporal; import static com.oracle.truffle.js.runtime.util.TemporalConstants.AUTO; -import static com.oracle.truffle.js.runtime.util.TemporalConstants.DAYS; import static com.oracle.truffle.js.runtime.util.TemporalConstants.HALF_EXPAND; -import static com.oracle.truffle.js.runtime.util.TemporalConstants.HOURS; -import static com.oracle.truffle.js.runtime.util.TemporalConstants.MICROSECONDS; -import static com.oracle.truffle.js.runtime.util.TemporalConstants.MILLISECONDS; -import static com.oracle.truffle.js.runtime.util.TemporalConstants.MINUTES; -import static com.oracle.truffle.js.runtime.util.TemporalConstants.MONTHS; -import static com.oracle.truffle.js.runtime.util.TemporalConstants.NANOSECONDS; -import static com.oracle.truffle.js.runtime.util.TemporalConstants.SECONDS; import static com.oracle.truffle.js.runtime.util.TemporalConstants.TRUNC; import static com.oracle.truffle.js.runtime.util.TemporalConstants.UNIT; -import static com.oracle.truffle.js.runtime.util.TemporalConstants.WEEKS; -import static com.oracle.truffle.js.runtime.util.TemporalConstants.YEARS; import static com.oracle.truffle.js.runtime.util.TemporalUtil.dtol; -import static com.oracle.truffle.js.runtime.util.TemporalUtil.getDouble; import java.util.EnumSet; @@ -77,7 +66,6 @@ import com.oracle.truffle.js.builtins.temporal.TemporalDurationPrototypeBuiltinsFactory.JSTemporalDurationTotalNodeGen; import com.oracle.truffle.js.builtins.temporal.TemporalDurationPrototypeBuiltinsFactory.JSTemporalDurationWithNodeGen; import com.oracle.truffle.js.nodes.cast.JSNumberToBigIntNode; -import com.oracle.truffle.js.nodes.cast.JSToIntegerWithoutRoundingNode; import com.oracle.truffle.js.nodes.function.JSBuiltin; import com.oracle.truffle.js.nodes.function.JSBuiltinNode; import com.oracle.truffle.js.nodes.temporal.CalendarMethodsRecordLookupNode; @@ -91,6 +79,7 @@ import com.oracle.truffle.js.nodes.temporal.ToFractionalSecondDigitsNode; import com.oracle.truffle.js.nodes.temporal.ToRelativeTemporalObjectNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalDurationNode; +import com.oracle.truffle.js.nodes.temporal.ToTemporalPartialDurationRecordNode; import com.oracle.truffle.js.runtime.Errors; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRealm; @@ -280,24 +269,12 @@ protected JSTemporalDurationWith(JSContext context, JSBuiltin builtin) { @Specialization protected JSTemporalDurationObject with(JSTemporalDurationObject duration, Object temporalDurationLike, - @Cached JSToIntegerWithoutRoundingNode toInt, + @Cached ToTemporalPartialDurationRecordNode toTemporalPartialDurationRecord, @Cached InlinedBranchProfile errorBranch) { - JSDynamicObject durationLike = TemporalUtil.toPartialDuration(temporalDurationLike, - getContext(), isObjectNode, toInt, this, errorBranch); - - double years = getDouble(durationLike, YEARS, duration.getYears()); - double months = getDouble(durationLike, MONTHS, duration.getMonths()); - double weeks = getDouble(durationLike, WEEKS, duration.getWeeks()); - double days = getDouble(durationLike, DAYS, duration.getDays()); - double hours = getDouble(durationLike, HOURS, duration.getHours()); - double minutes = getDouble(durationLike, MINUTES, duration.getMinutes()); - double seconds = getDouble(durationLike, SECONDS, duration.getSeconds()); - double milliseconds = getDouble(durationLike, MILLISECONDS, duration.getMilliseconds()); - double microseconds = getDouble(durationLike, MICROSECONDS, duration.getMicroseconds()); - double nanoseconds = getDouble(durationLike, NANOSECONDS, duration.getNanoseconds()); + JSTemporalDurationRecord r = toTemporalPartialDurationRecord.execute(temporalDurationLike, JSTemporalDurationRecord.create(duration)); return JSTemporalDuration.createTemporalDuration(getContext(), getRealm(), - years, months, weeks, days, - hours, minutes, seconds, milliseconds, microseconds, nanoseconds, + r.getYears(), r.getMonths(), r.getWeeks(), r.getDays(), + r.getHours(), r.getMinutes(), r.getSeconds(), r.getMilliseconds(), r.getMicroseconds(), r.getNanoseconds(), this, errorBranch); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalDurationNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalDurationNode.java index a2e51f7ef67..d424e031912 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalDurationNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalDurationNode.java @@ -43,15 +43,10 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.profiles.InlinedBranchProfile; -import com.oracle.truffle.api.profiles.InlinedConditionProfile; -import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.nodes.JavaScriptBaseNode; -import com.oracle.truffle.js.nodes.access.IsObjectNode; -import com.oracle.truffle.js.runtime.Errors; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDuration; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationObject; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationRecord; -import com.oracle.truffle.js.runtime.objects.JSDynamicObject; /** * Implementation of ToTemporalDuration() operation. @@ -65,22 +60,12 @@ protected ToTemporalDurationNode() { @Specialization protected JSTemporalDurationObject toTemporalDuration(Object item, - @Cached InlinedConditionProfile isObjectProfile, - @Cached InlinedBranchProfile errorBranch, - @Cached IsObjectNode isObjectNode) { - JSTemporalDurationRecord result; - if (isObjectProfile.profile(this, isObjectNode.executeBoolean(item))) { - JSDynamicObject itemObj = (JSDynamicObject) item; - if (JSTemporalDuration.isJSTemporalDuration(itemObj)) { - return (JSTemporalDurationObject) itemObj; - } - result = JSTemporalDuration.toTemporalDurationRecord(itemObj); - } else if (item instanceof TruffleString string) { - result = JSTemporalDuration.parseTemporalDurationString(string); - } else { - errorBranch.enter(this); - throw Errors.createTypeErrorNotAString(item); + @Cached ToTemporalDurationRecordNode toTemporalDurationRecord, + @Cached InlinedBranchProfile errorBranch) { + if (item instanceof JSTemporalDurationObject duration) { + return duration; } + JSTemporalDurationRecord result = toTemporalDurationRecord.execute(item); return JSTemporalDuration.createTemporalDuration(getLanguage().getJSContext(), getRealm(), result.getYears(), result.getMonths(), result.getWeeks(), result.getDays(), result.getHours(), result.getMinutes(), result.getSeconds(), result.getMilliseconds(), result.getMicroseconds(), result.getNanoseconds(), this, errorBranch); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalDurationRecordNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalDurationRecordNode.java new file mode 100644 index 00000000000..cfd95c78d88 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalDurationRecordNode.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.nodes.temporal; + +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.profiles.InlinedBranchProfile; +import com.oracle.truffle.api.profiles.InlinedConditionProfile; +import com.oracle.truffle.api.strings.TruffleString; +import com.oracle.truffle.js.nodes.JavaScriptBaseNode; +import com.oracle.truffle.js.nodes.access.IsObjectNode; +import com.oracle.truffle.js.runtime.Errors; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDuration; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationObject; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationRecord; +import com.oracle.truffle.js.runtime.util.TemporalErrors; +import com.oracle.truffle.js.runtime.util.TemporalUtil; + +/** + * Implementation of ToTemporalDurationRecord (temporalDurationLike) operation. + */ +public abstract class ToTemporalDurationRecordNode extends JavaScriptBaseNode { + + protected ToTemporalDurationRecordNode() { + } + + public abstract JSTemporalDurationRecord execute(Object item); + + @Specialization + protected final JSTemporalDurationRecord toTemporalDurationRecord(Object temporalDurationLike, + @Cached InlinedConditionProfile isObjectProfile, + @Cached ToTemporalPartialDurationRecordNode toTemporalPartialDurationRecord, + @Cached InlinedBranchProfile errorBranch, + @Cached IsObjectNode isObjectNode) { + JSTemporalDurationRecord result; + if (isObjectProfile.profile(this, isObjectNode.executeBoolean(temporalDurationLike))) { + if (temporalDurationLike instanceof JSTemporalDurationObject duration) { + result = JSTemporalDurationRecord.create(duration); + } else { + result = toTemporalPartialDurationRecord.execute(temporalDurationLike, JSTemporalDurationRecord.createZero()); + if (!TemporalUtil.isValidDuration(result.getYears(), result.getMonths(), result.getWeeks(), result.getDays(), + result.getHours(), result.getMinutes(), result.getSeconds(), result.getMilliseconds(), result.getMicroseconds(), result.getNanoseconds())) { + errorBranch.enter(this); + throw TemporalErrors.createTypeErrorDurationOutsideRange(); + } + } + } else if (temporalDurationLike instanceof TruffleString string) { + result = JSTemporalDuration.parseTemporalDurationString(string); + } else { + errorBranch.enter(this); + throw Errors.createTypeErrorNotAString(temporalDurationLike); + } + return result; + } +} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalPartialDurationRecordNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalPartialDurationRecordNode.java new file mode 100644 index 00000000000..9e8bf41adae --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalPartialDurationRecordNode.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.nodes.temporal; + +import static com.oracle.truffle.js.nodes.JSGuards.isUndefined; + +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.ImportStatic; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.profiles.InlinedBranchProfile; +import com.oracle.truffle.js.nodes.JavaScriptBaseNode; +import com.oracle.truffle.js.nodes.access.IsObjectNode; +import com.oracle.truffle.js.nodes.access.PropertyGetNode; +import com.oracle.truffle.js.nodes.cast.JSToIntegerWithoutRoundingNode; +import com.oracle.truffle.js.runtime.Errors; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationRecord; +import com.oracle.truffle.js.runtime.util.TemporalConstants; + +/** + * Implementation of ToTemporalPartialDurationRecord(temporalDurationLike) operation. + */ +@ImportStatic(TemporalConstants.class) +public abstract class ToTemporalPartialDurationRecordNode extends JavaScriptBaseNode { + + protected ToTemporalPartialDurationRecordNode() { + } + + public abstract JSTemporalDurationRecord execute(Object temporalDurationLike, JSTemporalDurationRecord defaults); + + @Specialization + protected final JSTemporalDurationRecord toTemporalPartialDurationRecord(Object temporalDurationLike, JSTemporalDurationRecord defaults, + @Cached IsObjectNode isObjectNode, + @Cached InlinedBranchProfile errorBranch, + @Cached JSToIntegerWithoutRoundingNode toIntegerIfIntegral, + @Cached("create(DAYS, getJSContext())") PropertyGetNode getDays, + @Cached("create(HOURS, getJSContext())") PropertyGetNode getHours, + @Cached("create(MICROSECONDS, getJSContext())") PropertyGetNode getMicroseconds, + @Cached("create(MILLISECONDS, getJSContext())") PropertyGetNode getMilliseconds, + @Cached("create(MINUTES, getJSContext())") PropertyGetNode getMinutes, + @Cached("create(MONTHS, getJSContext())") PropertyGetNode getMonths, + @Cached("create(NANOSECONDS, getJSContext())") PropertyGetNode getNanoseconds, + @Cached("create(SECONDS, getJSContext())") PropertyGetNode getSeconds, + @Cached("create(WEEKS, getJSContext())") PropertyGetNode getWeeks, + @Cached("create(YEARS, getJSContext())") PropertyGetNode getYears) { + if (!isObjectNode.executeBoolean(temporalDurationLike)) { + errorBranch.enter(this); + throw Errors.createTypeError("Given duration like is not a object."); + } + Object daysValue = getDays.getValue(temporalDurationLike); + double days = isUndefined(daysValue) ? defaults.getDays() : toIntegerIfIntegral.executeDouble(daysValue); + Object hoursValue = getHours.getValue(temporalDurationLike); + double hours = isUndefined(hoursValue) ? defaults.getHours() : toIntegerIfIntegral.executeDouble(hoursValue); + Object microsecondsValue = getMicroseconds.getValue(temporalDurationLike); + double microseconds = isUndefined(microsecondsValue) ? defaults.getMicroseconds() : toIntegerIfIntegral.executeDouble(microsecondsValue); + Object millisecondsValue = getMilliseconds.getValue(temporalDurationLike); + double milliseconds = isUndefined(millisecondsValue) ? defaults.getMilliseconds() : toIntegerIfIntegral.executeDouble(millisecondsValue); + Object minutesValue = getMinutes.getValue(temporalDurationLike); + double minutes = isUndefined(minutesValue) ? defaults.getMinutes() : toIntegerIfIntegral.executeDouble(minutesValue); + Object monthsValue = getMonths.getValue(temporalDurationLike); + double months = isUndefined(monthsValue) ? defaults.getMonths() : toIntegerIfIntegral.executeDouble(monthsValue); + Object nanosecondsValue = getNanoseconds.getValue(temporalDurationLike); + double nanoseconds = isUndefined(nanosecondsValue) ? defaults.getNanoseconds() : toIntegerIfIntegral.executeDouble(nanosecondsValue); + Object secondsValue = getSeconds.getValue(temporalDurationLike); + double seconds = isUndefined(secondsValue) ? defaults.getSeconds() : toIntegerIfIntegral.executeDouble(secondsValue); + Object weeksValue = getWeeks.getValue(temporalDurationLike); + double weeks = isUndefined(weeksValue) ? defaults.getWeeks() : toIntegerIfIntegral.executeDouble(weeksValue); + Object yearsValue = getYears.getValue(temporalDurationLike); + double years = isUndefined(yearsValue) ? defaults.getYears() : toIntegerIfIntegral.executeDouble(yearsValue); + if (isUndefined(yearsValue) && + isUndefined(monthsValue) && + isUndefined(weeksValue) && + isUndefined(daysValue) && + isUndefined(hoursValue) && + isUndefined(minutesValue) && + isUndefined(secondsValue) && + isUndefined(millisecondsValue) && + isUndefined(microsecondsValue) && + isUndefined(nanosecondsValue)) { + errorBranch.enter(this); + throw Errors.createTypeError("Given duration like object has no duration properties."); + } + return JSTemporalDurationRecord.createWeeks(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds); + } +} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalDuration.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalDuration.java index 1e921ad745d..281163218b0 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalDuration.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalDuration.java @@ -71,11 +71,9 @@ import com.oracle.truffle.js.runtime.objects.JSDynamicObject; import com.oracle.truffle.js.runtime.objects.JSObject; import com.oracle.truffle.js.runtime.objects.JSObjectUtil; -import com.oracle.truffle.js.runtime.objects.Undefined; import com.oracle.truffle.js.runtime.util.Pair; import com.oracle.truffle.js.runtime.util.TemporalErrors; import com.oracle.truffle.js.runtime.util.TemporalUtil; -import com.oracle.truffle.js.runtime.util.TemporalUtil.UnitPlural; public final class JSTemporalDuration extends JSNonProxy implements JSConstructorFactory.Default.WithFunctions, PrototypeSupplier { @@ -336,79 +334,6 @@ private static int findDecimalSeparator(TruffleString str, int startPos) { return idxComma; } - // 7.5.2 - @TruffleBoundary - public static JSTemporalDurationRecord toTemporalDurationRecord(JSDynamicObject temporalDurationLike) { - if (isJSTemporalDuration(temporalDurationLike)) { - JSTemporalDurationObject d = (JSTemporalDurationObject) temporalDurationLike; - return JSTemporalDurationRecord.createWeeks(d.getYears(), d.getMonths(), d.getWeeks(), d.getDays(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds(), - d.getMicroseconds(), d.getNanoseconds()); - } - boolean any = false; - double year = 0; - double month = 0; - double week = 0; - double day = 0; - double hour = 0; - double minute = 0; - double second = 0; - double millis = 0; - double micros = 0; - double nanos = 0; - for (UnitPlural unit : TemporalUtil.DURATION_PROPERTIES) { - Object val = JSObject.get(temporalDurationLike, unit.toTruffleString()); - - double lVal = 0; - if (val == Undefined.instance) { - lVal = 0; - } else { - any = true; - lVal = TemporalUtil.toIntegerWithoutRounding(val); - } - switch (unit) { - case YEARS: - year = lVal; - break; - case MONTHS: - month = lVal; - break; - case WEEKS: - week = lVal; - break; - case DAYS: - day = lVal; - break; - case HOURS: - hour = lVal; - break; - case MINUTES: - minute = lVal; - break; - case SECONDS: - second = lVal; - break; - case MILLISECONDS: - millis = lVal; - break; - case MICROSECONDS: - micros = lVal; - break; - case NANOSECONDS: - nanos = lVal; - break; - default: - throw Errors.unsupported("wrong type"); - } - } - if (!any) { - throw Errors.createTypeError("Given duration like object has no duration properties."); - } - if (!TemporalUtil.isValidDuration(year, month, week, day, hour, minute, second, millis, micros, nanos)) { - throw TemporalErrors.createTypeErrorDurationOutsideRange(); - } - return TemporalUtil.createDurationRecord(year, month, week, day, hour, minute, second, millis, micros, nanos); - } - @TruffleBoundary public static TruffleString temporalDurationToString(double yearsP, double monthsP, double weeksP, double daysP, double hoursP, double minutesP, double secondsP, double millisecondsP, double microsecondsP, double nanosecondsP, Object precision, JSNumberToBigIntNode toBigIntNode) { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalDurationRecord.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalDurationRecord.java index 2035b78a717..cd6c2bee985 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalDurationRecord.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalDurationRecord.java @@ -137,4 +137,7 @@ public static JSTemporalDurationRecord create(JSTemporalDurationObject duration) duration.getMilliseconds(), duration.getMicroseconds(), duration.getNanoseconds()); } + public static JSTemporalDurationRecord createZero() { + return new JSTemporalDurationRecord(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java index 46eb466fa29..f157d582a2f 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java @@ -123,10 +123,8 @@ import com.oracle.truffle.api.strings.TruffleStringBuilderUTF16; import com.oracle.truffle.js.lang.JavaScriptLanguage; import com.oracle.truffle.js.nodes.access.EnumerableOwnPropertyNamesNode; -import com.oracle.truffle.js.nodes.access.IsObjectNode; import com.oracle.truffle.js.nodes.cast.JSToIntegerOrInfinityNode; import com.oracle.truffle.js.nodes.cast.JSToIntegerThrowOnInfinityNode; -import com.oracle.truffle.js.nodes.cast.JSToIntegerWithoutRoundingNode; import com.oracle.truffle.js.nodes.temporal.CalendarMethodsRecordLookupNode; import com.oracle.truffle.js.nodes.temporal.TemporalCalendarDateFromFieldsNode; import com.oracle.truffle.js.nodes.temporal.TemporalCalendarGetterNode; @@ -277,8 +275,6 @@ public final class TemporalUtil { public static final List listDisambiguation = List.of(COMPATIBLE, EARLIER, LATER, REJECT); public static final TruffleString[] TIME_LIKE_PROPERTIES = new TruffleString[]{HOUR, MICROSECOND, MILLISECOND, MINUTE, NANOSECOND, SECOND}; - public static final UnitPlural[] DURATION_PROPERTIES = new UnitPlural[]{UnitPlural.DAYS, UnitPlural.HOURS, UnitPlural.MICROSECONDS, UnitPlural.MILLISECONDS, - UnitPlural.MINUTES, UnitPlural.MONTHS, UnitPlural.NANOSECONDS, UnitPlural.SECONDS, UnitPlural.WEEKS, UnitPlural.YEARS}; private static final BigInt upperEpochNSLimit = new BigInt(BigInteger.valueOf(86400).multiply(BigInteger.valueOf(10).pow(17))); private static final BigInt lowerEpochNSLimit = upperEpochNSLimit.negate(); @@ -2327,31 +2323,6 @@ public static Unit defaultTemporalLargestUnit(double years, double months, doubl return Unit.NANOSECOND; } - @TruffleBoundary - public static JSDynamicObject toPartialDuration(Object temporalDurationLike, - JSContext ctx, IsObjectNode isObjectNode, JSToIntegerWithoutRoundingNode toInt, Node node, InlinedBranchProfile errorBranch) { - if (!isObjectNode.executeBoolean(temporalDurationLike)) { - errorBranch.enter(node); - throw Errors.createTypeError("Given duration like is not a object."); - } - JSDynamicObject temporalDurationLikeObj = toJSDynamicObject(temporalDurationLike, node, errorBranch); - JSRealm realm = JSRealm.get(null); - JSDynamicObject result = JSOrdinary.create(ctx, realm); - boolean any = false; - for (UnitPlural unit : DURATION_PROPERTIES) { - Object value = JSObject.get(temporalDurationLikeObj, unit.toTruffleString()); - if (value != Undefined.instance) { - any = true; - JSObjectUtil.putDataProperty(result, unit.toTruffleString(), toInt.executeDouble(value)); - } - } - if (!any) { - errorBranch.enter(node); - throw Errors.createTypeError("Given duration like object has no duration properties."); - } - return result; - } - @TruffleBoundary public static double roundDurationCalculateFractionalSeconds(double seconds, double milliseconds, double microseconds, double nanoseconds) { assert JSRuntime.isIntegralNumber(seconds) && JSRuntime.isIntegralNumber(milliseconds) && JSRuntime.isIntegralNumber(microseconds) && JSRuntime.isIntegralNumber(nanoseconds); From e9035bb23029fc43aa1ea4a7ee236e63b9fc15c7 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 4 Jun 2024 11:33:02 +0200 Subject: [PATCH 009/265] Use shouldNotReachHere for unexpected, already checked, option value. --- .../com/oracle/truffle/js/runtime/util/TemporalUtil.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java index f157d582a2f..df9a3ca2e9c 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java @@ -3717,7 +3717,7 @@ public static RoundingMode toRoundingMode(TruffleString mode, TruffleString.Equa } else if (equalNode.execute(mode, HALF_EVEN, TruffleString.Encoding.UTF_16)) { return RoundingMode.HALF_EVEN; } - throw Errors.createTypeError("unexpected roundingMode"); + throw Errors.shouldNotReachHereUnexpectedValue(mode); } @TruffleBoundary @@ -3731,7 +3731,7 @@ public static Disambiguation toDisambiguation(TruffleString disambiguation, Truf } else if (equalNode.execute(disambiguation, REJECT, TruffleString.Encoding.UTF_16)) { return Disambiguation.REJECT; } - throw Errors.createTypeError("unexpected disambiguation"); + throw Errors.shouldNotReachHereUnexpectedValue(disambiguation); } @TruffleBoundary @@ -3745,7 +3745,7 @@ public static OffsetOption toOffsetOption(TruffleString offsetOption, TruffleStr } else if (equalNode.execute(offsetOption, REJECT, TruffleString.Encoding.UTF_16)) { return OffsetOption.REJECT; } - throw Errors.createTypeError("unexpected offsetOption"); + throw Errors.shouldNotReachHereUnexpectedValue(offsetOption); } public static ShowCalendar toShowCalendar(TruffleString showCalendar, TruffleString.EqualNode equalNode) { @@ -3758,7 +3758,7 @@ public static ShowCalendar toShowCalendar(TruffleString showCalendar, TruffleStr } else if (Strings.equals(equalNode, showCalendar, CRITICAL)) { return ShowCalendar.CRITICAL; } - throw Errors.createTypeError("unexpected showCalendar"); + throw Errors.shouldNotReachHereUnexpectedValue(showCalendar); } public static double roundTowardsZero(double d) { From 30538db3238257ae2c245fa41f750fc21853492f Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 4 Jun 2024 11:24:00 +0200 Subject: [PATCH 010/265] Apply TruffleBoundary to more TemporalUtil methods. --- .../src/com/oracle/truffle/js/runtime/util/TemporalUtil.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java index df9a3ca2e9c..e4d36e2baf7 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java @@ -488,6 +488,7 @@ public static double validateTemporalRoundingIncrement(double increment, double return increment; } + @TruffleBoundary public static JSTemporalPrecisionRecord toSecondsStringPrecisionRecord(Unit smallestUnit, int fractionalDigitCount) { return switch (smallestUnit) { case MINUTE -> JSTemporalPrecisionRecord.create(MINUTE, Unit.MINUTE, 1); @@ -1033,6 +1034,7 @@ public static int toISODayOfYear(int year, int month, int day) { } // ToISOWeekOfYear(year, month, day).[[Week]] + @TruffleBoundary public static long weekOfToISOWeekOfYear(int year, int month, int day) { long wednesday = 3; long thursday = 4; @@ -1065,6 +1067,7 @@ public static long weekOfToISOWeekOfYear(int year, int month, int day) { } // ToISOWeekOfYear(year, month, day).[[Year]] + @TruffleBoundary public static long yearOfToISOWeekOfYear(int year, int month, int day) { long wednesday = 3; long thursday = 4; From 794a4add4bb6a60e85167fcfa065f48cb2d7e19f Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 4 Jun 2024 11:54:47 +0200 Subject: [PATCH 011/265] Simplify largerOfTwoTemporalUnits and validateTemporalUnitRange. --- .../truffle/js/runtime/util/TemporalUtil.java | 81 +------------------ 1 file changed, 4 insertions(+), 77 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java index e4d36e2baf7..73d7166e0ac 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java @@ -605,55 +605,7 @@ private static ParseISODateTimeResult parseISODateTimeIntl(TruffleString string, } public static void validateTemporalUnitRange(Unit largestUnit, Unit smallestUnit) { - boolean error = false; - switch (smallestUnit) { - case YEAR: - if (!(largestUnit == Unit.YEAR)) { - error = true; - } - break; - case MONTH: - if (!(largestUnit == Unit.YEAR || largestUnit == Unit.MONTH)) { - error = true; - } - break; - case WEEK: - if (!(largestUnit == Unit.YEAR || largestUnit == Unit.MONTH || largestUnit == Unit.WEEK)) { - error = true; - } - break; - case DAY: - if (!(largestUnit == Unit.YEAR || largestUnit == Unit.MONTH || largestUnit == Unit.WEEK || largestUnit == Unit.DAY)) { - error = true; - } - break; - case HOUR: - if (!(largestUnit == Unit.YEAR || largestUnit == Unit.MONTH || largestUnit == Unit.WEEK || largestUnit == Unit.DAY || largestUnit == Unit.HOUR)) { - error = true; - } - break; - case MINUTE: - if (largestUnit == Unit.SECOND || largestUnit == Unit.MILLISECOND || largestUnit == Unit.MICROSECOND || largestUnit == Unit.NANOSECOND) { - error = true; - } - break; - case SECOND: - if (largestUnit == Unit.MILLISECOND || largestUnit == Unit.MICROSECOND || largestUnit == Unit.NANOSECOND) { - error = true; - } - break; - case MILLISECOND: - if (largestUnit == Unit.MICROSECOND || largestUnit == Unit.NANOSECOND) { - error = true; - } - break; - case MICROSECOND: - if (largestUnit == Unit.NANOSECOND) { - error = true; - } - break; - } - if (error) { + if (largerOfTwoTemporalUnits(largestUnit, smallestUnit) != largestUnit) { throw TemporalErrors.createRangeErrorSmallestUnitOutOfRange(); } } @@ -1777,34 +1729,9 @@ public static List listJoinRemoveDuplicates(List f } public static Unit largerOfTwoTemporalUnits(Unit a, Unit b) { - if (Unit.YEAR == a || Unit.YEAR == b) { - return Unit.YEAR; - } - if (Unit.MONTH == a || Unit.MONTH == b) { - return Unit.MONTH; - } - if (Unit.WEEK == a || Unit.WEEK == b) { - return Unit.WEEK; - } - if (Unit.DAY == a || Unit.DAY == b) { - return Unit.DAY; - } - if (Unit.HOUR == a || Unit.HOUR == b) { - return Unit.HOUR; - } - if (Unit.MINUTE == a || Unit.MINUTE == b) { - return Unit.MINUTE; - } - if (Unit.SECOND == a || Unit.SECOND == b) { - return Unit.SECOND; - } - if (Unit.MILLISECOND == a || Unit.MILLISECOND == b) { - return Unit.MILLISECOND; - } - if (Unit.MICROSECOND == a || Unit.MICROSECOND == b) { - return Unit.MICROSECOND; - } - return Unit.NANOSECOND; + assert Unit.YEAR.compareTo(a) <= 0 && a.compareTo(Unit.NANOSECOND) <= 0 : a; + assert Unit.YEAR.compareTo(b) <= 0 && b.compareTo(Unit.NANOSECOND) <= 0 : b; + return a.compareTo(b) <= 0 ? a : b; } @TruffleBoundary From dbe097cff6c51ce4252ec06e5994901fdacc900f Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Fri, 7 Jun 2024 14:37:33 +0200 Subject: [PATCH 012/265] Make roundingIncrement an int. --- .../TemporalDurationPrototypeBuiltins.java | 8 ++-- .../TemporalInstantPrototypeBuiltins.java | 8 ++-- ...emporalPlainDateTimePrototypeBuiltins.java | 13 ++----- .../TemporalPlainTimePrototypeBuiltins.java | 11 +----- ...emporalZonedDateTimePrototypeBuiltins.java | 13 ++----- .../temporal/GetDifferenceSettingsNode.java | 8 ++-- .../GetRoundingIncrementOptionNode.java | 6 +-- .../temporal/TemporalDurationAddNode.java | 4 +- .../temporal/TemporalRoundDurationNode.java | 28 +++++++------- .../temporal/JSTemporalPrecisionRecord.java | 8 ++-- .../truffle/js/runtime/util/TemporalUtil.java | 38 +++++++++---------- 11 files changed, 62 insertions(+), 83 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java index 39defa8cfdb..2ba32eb4de6 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java @@ -416,7 +416,7 @@ protected JSTemporalDurationObject round(JSTemporalDurationObject duration, Obje JSTemporalZonedDateTimeObject zonedRelativeTo = relativeToRec.zonedRelativeTo(); JSTemporalPlainDateObject plainRelativeTo = relativeToRec.plainRelativeTo(); TimeZoneMethodsRecord timeZoneRec = relativeToRec.timeZoneRec(); - double roundingIncrement = getRoundingIncrementOption.execute(roundTo); + int roundingIncrement = getRoundingIncrementOption.execute(roundTo); RoundingMode roundingMode = toTemporalRoundingMode(roundTo, HALF_EXPAND, equalNode, getOptionNode); Unit smallestUnit = getSmallestUnit.execute(roundTo, TemporalConstants.SMALLEST_UNIT, TemporalUtil.unitMappingDateTime, Unit.EMPTY); if (smallestUnit == Unit.EMPTY) { @@ -440,7 +440,7 @@ protected JSTemporalDurationObject round(JSTemporalDurationObject duration, Obje } JSRealm realm = getRealm(); TemporalUtil.validateTemporalUnitRange(largestUnit, smallestUnit); - Double maximum = TemporalUtil.maximumTemporalDurationRoundingIncrement(smallestUnit); + Integer maximum = TemporalUtil.maximumTemporalDurationRoundingIncrement(smallestUnit); if (maximum != null) { TemporalUtil.validateTemporalRoundingIncrement(roundingIncrement, maximum, false, node, errorBranch); } @@ -488,7 +488,7 @@ protected JSTemporalDurationObject round(JSTemporalDurationObject duration, Obje JSTemporalDurationRecord roundResult = roundDurationNode.execute( unbalanceResult.getYears(), unbalanceResult.getMonths(), unbalanceResult.getWeeks(), unbalanceResult.getDays(), duration.getHours(), duration.getMinutes(), duration.getSeconds(), duration.getMilliseconds(), - duration.getMicroseconds(), duration.getNanoseconds(), (long) roundingIncrement, smallestUnit, + duration.getMicroseconds(), duration.getNanoseconds(), roundingIncrement, smallestUnit, roundingMode, plainRelativeTo, zonedRelativeTo, calendarRec, timeZoneRec, precalculatedPlainDateTime); TimeDurationRecord balanceResult; if (relativeToIsZonedDateTime.profile(node, zonedRelativeTo != null)) { @@ -496,7 +496,7 @@ protected JSTemporalDurationObject round(JSTemporalDurationObject duration, Obje roundResult.getYears(), roundResult.getMonths(), roundResult.getWeeks(), roundResult.getDays(), roundResult.getHours(), roundResult.getMinutes(), roundResult.getSeconds(), roundResult.getMilliseconds(), roundResult.getMicroseconds(), roundResult.getNanoseconds(), - (long) roundingIncrement, smallestUnit, roundingMode, + roundingIncrement, smallestUnit, roundingMode, zonedRelativeTo, calendarRec, timeZoneRec, precalculatedPlainDateTime); balanceResult = TemporalUtil.balanceTimeDurationRelative(adjustResult.getDays(), adjustResult.getHours(), adjustResult.getMinutes(), adjustResult.getSeconds(), adjustResult.getMilliseconds(), adjustResult.getMicroseconds(), adjustResult.getNanoseconds(), largestUnit, diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalInstantPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalInstantPrototypeBuiltins.java index 5f3cbc97d4b..099a2f8b0de 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalInstantPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalInstantPrototypeBuiltins.java @@ -314,10 +314,10 @@ protected JSTemporalInstantObject round(JSTemporalInstantObject instant, Object } else { roundTo = getOptionsObject(roundToParam, this, errorBranch, optionUndefined); } - double roundingIncrement = getRoundingIncrementOption.execute(roundTo); + int roundingIncrement = getRoundingIncrementOption.execute(roundTo); RoundingMode roundingMode = toTemporalRoundingMode(roundTo, HALF_EXPAND, equalNode, getOptionNode); Unit smallestUnit = getSmallestUnit.execute(roundTo, TemporalConstants.SMALLEST_UNIT, TemporalUtil.unitMappingTime, Unit.REQUIRED); - double maximum; + long maximum; if (Unit.HOUR == smallestUnit) { maximum = TemporalUtil.HOURS_PER_DAY; } else if (Unit.MINUTE == smallestUnit) { @@ -330,10 +330,10 @@ protected JSTemporalInstantObject round(JSTemporalInstantObject instant, Object maximum = TemporalUtil.MS_PER_DAY * 1000; } else { assert Unit.NANOSECOND == smallestUnit; - maximum = TemporalUtil.NS_PER_DAY; + maximum = TemporalUtil.NS_PER_DAY_LONG; } TemporalUtil.validateTemporalRoundingIncrement(roundingIncrement, maximum, true, this, errorBranch); - BigInt roundedNs = TemporalUtil.roundTemporalInstant(instant.getNanoseconds(), (long) roundingIncrement, smallestUnit, roundingMode); + BigInt roundedNs = TemporalUtil.roundTemporalInstant(instant.getNanoseconds(), roundingIncrement, smallestUnit, roundingMode); return JSTemporalInstant.create(getContext(), getRealm(), roundedNs); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainDateTimePrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainDateTimePrototypeBuiltins.java index 270dc75a143..52c20429f72 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainDateTimePrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainDateTimePrototypeBuiltins.java @@ -740,23 +740,16 @@ final JSTemporalPlainDateTimeObject round(JSTemporalPlainDateTimeObject dt, Obje } else { roundTo = getOptionsObject(roundToParam, this, errorBranch, optionUndefined); } - double roundingIncrement = getRoundingIncrementOption.execute(roundTo); + int roundingIncrement = getRoundingIncrementOption.execute(roundTo); RoundingMode roundingMode = toTemporalRoundingMode(roundTo, HALF_EXPAND, equalNode, getOptionNode); Unit smallestUnit = getSmallestUnit.execute(roundTo, TemporalConstants.SMALLEST_UNIT, TemporalUtil.unitMappingTimeOrDay, Unit.REQUIRED); - double maximum; + int maximum; boolean inclusive; if (Unit.DAY == smallestUnit) { maximum = 1; inclusive = true; } else { - if (Unit.HOUR == smallestUnit) { - maximum = 24; - } else if (Unit.MINUTE == smallestUnit || Unit.SECOND == smallestUnit) { - maximum = 60; - } else { - assert Unit.MILLISECOND == smallestUnit || Unit.MICROSECOND == smallestUnit || Unit.NANOSECOND == smallestUnit; - maximum = 1000; - } + maximum = TemporalUtil.maximumTemporalDurationRoundingIncrement(smallestUnit); inclusive = false; } TemporalUtil.validateTemporalRoundingIncrement(roundingIncrement, maximum, inclusive, this, errorBranch); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainTimePrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainTimePrototypeBuiltins.java index a4b889aeb5a..3c1053169ed 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainTimePrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainTimePrototypeBuiltins.java @@ -429,17 +429,10 @@ protected JSTemporalPlainTimeObject round(JSTemporalPlainTimeObject temporalTime } else { roundTo = getOptionsObject(roundToParam, this, errorBranch, optionUndefined); } - double roundingIncrement = getRoundingIncrementOption.execute(roundTo); + int roundingIncrement = getRoundingIncrementOption.execute(roundTo); RoundingMode roundingMode = toTemporalRoundingMode(roundTo, HALF_EXPAND, equalNode, getOptionNode); Unit smallestUnit = getSmallestUnit.execute(roundTo, TemporalConstants.SMALLEST_UNIT, TemporalUtil.unitMappingTime, Unit.REQUIRED); - double maximum; - if (smallestUnit == Unit.HOUR) { - maximum = 24; - } else if (smallestUnit == Unit.MINUTE || smallestUnit == Unit.SECOND) { - maximum = 60; - } else { - maximum = 1000; - } + int maximum = TemporalUtil.maximumTemporalDurationRoundingIncrement(smallestUnit); TemporalUtil.validateTemporalRoundingIncrement(roundingIncrement, maximum, false, this, errorBranch); TimeRecord result = TemporalUtil.roundTime(temporalTime.getHour(), temporalTime.getMinute(), temporalTime.getSecond(), temporalTime.getMillisecond(), temporalTime.getMicrosecond(), diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalZonedDateTimePrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalZonedDateTimePrototypeBuiltins.java index 1eddc6659e7..def2a7ef7b5 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalZonedDateTimePrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalZonedDateTimePrototypeBuiltins.java @@ -937,23 +937,16 @@ protected JSDynamicObject round(JSTemporalZonedDateTimeObject zonedDateTime, Obj } else { roundTo = getOptionsObject(roundToParam, this, errorBranch, optionUndefined); } - double roundingIncrement = getRoundingIncrementOption.execute(roundTo); + int roundingIncrement = getRoundingIncrementOption.execute(roundTo); RoundingMode roundingMode = toTemporalRoundingMode(roundTo, HALF_EXPAND, equalNode, getOptionNode); Unit smallestUnit = getSmallestUnit.execute(roundTo, TemporalConstants.SMALLEST_UNIT, TemporalUtil.unitMappingTimeOrDay, Unit.REQUIRED); - double maximum; + int maximum; boolean inclusive; if (Unit.DAY == smallestUnit) { maximum = 1; inclusive = true; } else { - if (Unit.HOUR == smallestUnit) { - maximum = 24; - } else if (Unit.MINUTE == smallestUnit || Unit.SECOND == smallestUnit) { - maximum = 60; - } else { - assert Unit.MILLISECOND == smallestUnit || Unit.MICROSECOND == smallestUnit || Unit.NANOSECOND == smallestUnit; - maximum = 1000; - } + maximum = TemporalUtil.maximumTemporalDurationRoundingIncrement(smallestUnit); inclusive = false; } TemporalUtil.validateTemporalRoundingIncrement(roundingIncrement, maximum, inclusive, this, errorBranch); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/GetDifferenceSettingsNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/GetDifferenceSettingsNode.java index 2f3ff8b5078..a2658e3b0a1 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/GetDifferenceSettingsNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/GetDifferenceSettingsNode.java @@ -69,7 +69,7 @@ public record GetDifferenceSettingsResult( TemporalUtil.Unit smallestUnit, TemporalUtil.Unit largestUnit, TemporalUtil.RoundingMode roundingMode, - long roundingIncrement) { + int roundingIncrement) { } public abstract GetDifferenceSettingsResult execute(int operation, JSDynamicObject options, Map unitMappingOrAuto, Map unitMapping, @@ -86,7 +86,7 @@ final GetDifferenceSettingsResult getDifferenceSettings(int operation, JSDynamic @Cached GetTemporalUnitNode getSmallestUnit) { assert unitMappingOrAuto.containsKey(TemporalConstants.AUTO) && !unitMapping.containsKey(TemporalConstants.AUTO); Unit largestUnit = getLargestUnit.execute(resolvedOptions, TemporalConstants.LARGEST_UNIT, unitMappingOrAuto, Unit.AUTO); - double roundingIncrement = getRoundingIncrementOption.execute(resolvedOptions); + int roundingIncrement = getRoundingIncrementOption.execute(resolvedOptions); RoundingMode roundingMode = JSTemporalBuiltinOperation.toTemporalRoundingMode(resolvedOptions, TemporalConstants.TRUNC, equalNode, getOptionNode); if (operation == TemporalUtil.SINCE) { roundingMode = TemporalUtil.negateTemporalRoundingMode(roundingMode); @@ -97,10 +97,10 @@ final GetDifferenceSettingsResult getDifferenceSettings(int operation, JSDynamic largestUnit = defaultLargestUnit; } TemporalUtil.validateTemporalUnitRange(largestUnit, smallestUnit); - Double maximum = TemporalUtil.maximumTemporalDurationRoundingIncrement(smallestUnit); + Integer maximum = TemporalUtil.maximumTemporalDurationRoundingIncrement(smallestUnit); if (maximum != null) { TemporalUtil.validateTemporalRoundingIncrement(roundingIncrement, maximum, false, this, errorBranch); } - return new GetDifferenceSettingsResult(smallestUnit, largestUnit, roundingMode, (long) roundingIncrement); + return new GetDifferenceSettingsResult(smallestUnit, largestUnit, roundingMode, roundingIncrement); } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/GetRoundingIncrementOptionNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/GetRoundingIncrementOptionNode.java index 84fd5fce6d2..b5cbada673c 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/GetRoundingIncrementOptionNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/GetRoundingIncrementOptionNode.java @@ -54,10 +54,10 @@ @ImportStatic(TemporalConstants.class) public abstract class GetRoundingIncrementOptionNode extends JavaScriptBaseNode { - public abstract double execute(Object options); + public abstract int execute(Object options); @Specialization - protected final double toTemporalRoundingIncrement(Object options, + protected final int toTemporalRoundingIncrement(Object options, @Cached("create(ROUNDING_INCREMENT, getJSContext())") PropertyGetNode getRoundingIncrement, @Cached JSToDoubleNode toDouble, @Cached InlinedBranchProfile errorBranch) { @@ -71,7 +71,7 @@ protected final double toTemporalRoundingIncrement(Object options, errorBranch.enter(this); throw Errors.createRangeError("Increment out of range."); } - return increment; + return (int) increment; } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalDurationAddNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalDurationAddNode.java index 5bd7fc3ec1e..343d29f1a89 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalDurationAddNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalDurationAddNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -146,7 +146,7 @@ protected JSTemporalDurationRecord add(double y1, double mon1, double w1, double dtol(y2), dtol(mon2), dtol(w2), dtol(d2), dtol(h2), dtol(min2), dtol(s2), dtol(ms2), dtol(mus2), dtol(ns2), precalculatedPlainDateTime); if (largetUnitYMWDProfile.profile(this, TemporalUtil.Unit.YEAR != largestUnit && TemporalUtil.Unit.MONTH != largestUnit && TemporalUtil.Unit.WEEK != largestUnit && TemporalUtil.Unit.DAY != largestUnit)) { - TimeDurationRecord result = TemporalUtil.differenceInstant(zonedRelativeTo.getNanoseconds(), endNs, 1d, + TimeDurationRecord result = TemporalUtil.differenceInstant(zonedRelativeTo.getNanoseconds(), endNs, 1, TemporalUtil.Unit.NANOSECOND, largestUnit, TemporalUtil.RoundingMode.HALF_EXPAND, roundDurationNode); return TemporalUtil.createDurationRecord(0, 0, 0, 0, result.hours(), result.minutes(), result.seconds(), result.milliseconds(), result.microseconds(), result.nanoseconds()); } else { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalRoundDurationNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalRoundDurationNode.java index ec962fa2158..89f7c9ad8a3 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalRoundDurationNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalRoundDurationNode.java @@ -83,14 +83,14 @@ protected TemporalRoundDurationNode() { } public final JSTemporalDurationRecord execute(double y, double m, double w, double d, double h, double min, - double sec, double milsec, double micsec, double nsec, double increment, + double sec, double milsec, double micsec, double nsec, int increment, TemporalUtil.Unit unit, TemporalUtil.RoundingMode roundingMode) { return execute(y, m, w, d, h, min, sec, milsec, micsec, nsec, increment, unit, roundingMode, null, null, null, null, null); } public final JSTemporalDurationRecord execute(double y, double m, double w, double d, double h, double min, - double sec, double milsec, double micsec, double nsec, double increment, + double sec, double milsec, double micsec, double nsec, int increment, TemporalUtil.Unit unit, TemporalUtil.RoundingMode roundingMode, JSTemporalPlainDateObject plainRelativeTo, CalendarMethodsRecord calendarRec) { @@ -99,7 +99,7 @@ public final JSTemporalDurationRecord execute(double y, double m, double w, doub } public abstract JSTemporalDurationRecord execute(double y, double m, double w, double d, double h, double min, - double sec, double milsec, double micsec, double nsec, double increment, + double sec, double milsec, double micsec, double nsec, int increment, TemporalUtil.Unit unit, TemporalUtil.RoundingMode roundingMode, JSTemporalPlainDateObject plainRelativeTo, JSTemporalZonedDateTimeObject zonedRelativeTo, CalendarMethodsRecord calendarRec, TimeZoneMethodsRecord timeZoneRec, @@ -108,7 +108,7 @@ public abstract JSTemporalDurationRecord execute(double y, double m, double w, d // @Cached parameters create unused variable in generated code, see GR-37931 @Specialization protected JSTemporalDurationRecord round(double years, double months, double weeks, double d, double h, double min, - double sec, double milsec, double micsec, double nsec, double increment, + double sec, double milsec, double micsec, double nsec, int increment, TemporalUtil.Unit unit, TemporalUtil.RoundingMode roundingMode, JSTemporalPlainDateObject plainRelativeTo, JSTemporalZonedDateTimeObject zonedRelativeTo, CalendarMethodsRecord calendarRec, TimeZoneMethodsRecord timeZoneRec, @@ -201,7 +201,7 @@ protected JSTemporalDurationRecord round(double years, double months, double wee throw Errors.shouldNotReachHere(); } - private static JSTemporalDurationRecord getUnitNanosecond(double increment, TemporalUtil.RoundingMode roundingMode, final double years, final double months, final double weeks, final double days, + private static JSTemporalDurationRecord getUnitNanosecond(int increment, TemporalUtil.RoundingMode roundingMode, final double years, final double months, final double weeks, final double days, final double hours, final double minutes, final double seconds, final double microseconds, final double milliseconds, final double nanosecondsP) { double nanoseconds = nanosecondsP; double remainder = nanoseconds; @@ -210,7 +210,7 @@ private static JSTemporalDurationRecord getUnitNanosecond(double increment, Temp return JSTemporalDurationRecord.createWeeksRemainder(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, remainder); } - private static JSTemporalDurationRecord getUnitMicrosecond(double increment, TemporalUtil.RoundingMode roundingMode, final double years, final double months, final double weeks, final double days, + private static JSTemporalDurationRecord getUnitMicrosecond(int increment, TemporalUtil.RoundingMode roundingMode, final double years, final double months, final double weeks, final double days, final double hours, final double minutes, final double seconds, final double microsecondsP, final double milliseconds, final double nanoseconds) { double microseconds = microsecondsP; double fractionalMicroseconds = (nanoseconds * 0.001) + microseconds; @@ -219,7 +219,7 @@ private static JSTemporalDurationRecord getUnitMicrosecond(double increment, Tem return JSTemporalDurationRecord.createWeeksRemainder(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, 0, remainder); } - private static JSTemporalDurationRecord getUnitMillisecond(double increment, TemporalUtil.RoundingMode roundingMode, final double years, final double months, final double weeks, final double days, + private static JSTemporalDurationRecord getUnitMillisecond(int increment, TemporalUtil.RoundingMode roundingMode, final double years, final double months, final double weeks, final double days, final double hours, final double minutes, final double seconds, final double microseconds, final double millisecondsP, final double nanoseconds) { double milliseconds = millisecondsP; double fractionalMilliseconds = (nanoseconds * 0.000_001) + (microseconds * 0.001) + milliseconds; @@ -228,7 +228,7 @@ private static JSTemporalDurationRecord getUnitMillisecond(double increment, Tem return JSTemporalDurationRecord.createWeeksRemainder(years, months, weeks, days, hours, minutes, seconds, milliseconds, 0, 0, remainder); } - private static JSTemporalDurationRecord getUnitMinute(double increment, TemporalUtil.RoundingMode roundingMode, final double years, final double months, final double weeks, final double days, + private static JSTemporalDurationRecord getUnitMinute(int increment, TemporalUtil.RoundingMode roundingMode, final double years, final double months, final double weeks, final double days, final double hours, final double minutesP, double fractionalSeconds) { double minutes = minutesP; double fractionalMinutes = (fractionalSeconds / 60) + minutes; @@ -237,7 +237,7 @@ private static JSTemporalDurationRecord getUnitMinute(double increment, Temporal return JSTemporalDurationRecord.createWeeksRemainder(years, months, weeks, days, hours, minutes, 0, 0, 0, 0, remainder); } - private static JSTemporalDurationRecord getUnitHour(double increment, TemporalUtil.RoundingMode roundingMode, final double years, final double months, final double weeks, final double days, + private static JSTemporalDurationRecord getUnitHour(int increment, TemporalUtil.RoundingMode roundingMode, final double years, final double months, final double weeks, final double days, final double hoursP, final double minutes, double fractionalSeconds) { double hours = hoursP; double fractionalHours = (((fractionalSeconds / 60) + minutes) / 60) + hours; @@ -246,7 +246,7 @@ private static JSTemporalDurationRecord getUnitHour(double increment, TemporalUt return JSTemporalDurationRecord.createWeeksRemainder(years, months, weeks, days, hours, 0, 0, 0, 0, 0, remainder); } - private static JSTemporalDurationRecord getUnitDay(double increment, TemporalUtil.RoundingMode roundingMode, final double years, final double months, final double weeks, final double daysP, + private static JSTemporalDurationRecord getUnitDay(int increment, TemporalUtil.RoundingMode roundingMode, final double years, final double months, final double weeks, final double daysP, final double hours, final double minutes, final double seconds, final double microseconds, final double milliseconds, final double nanoseconds) { double fractionalDays = daysP; double days = TemporalUtil.roundNumberToIncrement(daysP, increment, roundingMode); @@ -254,7 +254,7 @@ private static JSTemporalDurationRecord getUnitDay(double increment, TemporalUti return JSTemporalDurationRecord.createWeeksRemainder(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, remainder); } - private JSTemporalDurationRecord getUnitWeek(double increment, TemporalUtil.RoundingMode roundingMode, + private JSTemporalDurationRecord getUnitWeek(int increment, TemporalUtil.RoundingMode roundingMode, final double years, final double months, final double weeksP, final double daysP, final double hours, final double minutes, final double seconds, final double microseconds, final double milliseconds, final double nanoseconds, JSTemporalPlainDateObject relativeToP, CalendarMethodsRecord calendarRec, @@ -294,7 +294,7 @@ private JSTemporalDurationRecord getUnitWeek(double increment, TemporalUtil.Roun return JSTemporalDurationRecord.createWeeksRemainder(years, months, weeks, 0, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, remainder); } - private JSTemporalDurationRecord getUnitMonth(double increment, TemporalUtil.RoundingMode roundingMode, + private JSTemporalDurationRecord getUnitMonth(int increment, TemporalUtil.RoundingMode roundingMode, final double years, final double monthsP, final double weeks, final double daysP, final double hours, final double minutes, final double seconds, final double microseconds, final double milliseconds, final double nanoseconds, JSTemporalPlainDateObject relativeToP, CalendarMethodsRecord calendarRec, @@ -343,7 +343,7 @@ private JSTemporalDurationRecord getUnitMonth(double increment, TemporalUtil.Rou } @TruffleBoundary - private static JSTemporalDurationRecord getUnitSecond(double increment, TemporalUtil.RoundingMode roundingMode, + private static JSTemporalDurationRecord getUnitSecond(int increment, TemporalUtil.RoundingMode roundingMode, double years, double months, double weeks, double days, double hours, double minutes, double fractionalSeconds) { double seconds = TemporalUtil.roundNumberToIncrement(fractionalSeconds, increment, roundingMode); @@ -351,7 +351,7 @@ private static JSTemporalDurationRecord getUnitSecond(double increment, Temporal return JSTemporalDurationRecord.createWeeksRemainder(years, months, weeks, days, hours, minutes, seconds, 0, 0, 0, remainder); } - private JSTemporalDurationRecord getUnitYear(final double increment, TemporalUtil.RoundingMode roundingMode, + private JSTemporalDurationRecord getUnitYear(final int increment, TemporalUtil.RoundingMode roundingMode, final double yearsP, final double months, final double weeks, final double daysP, final double hours, final double minutes, final double seconds, final double microseconds, final double milliseconds, final double nanoseconds, JSTemporalPlainDateObject relativeToP, CalendarMethodsRecord calendarRec, diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalPrecisionRecord.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalPrecisionRecord.java index 708a1d61c27..9487c021bd1 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalPrecisionRecord.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalPrecisionRecord.java @@ -48,16 +48,16 @@ public final class JSTemporalPrecisionRecord { private final Object precision; // TruffleString "minute", "auto", or an integer from 0 to 9 private final Unit unit; - private final double increment; + private final int increment; - private JSTemporalPrecisionRecord(Object precision, Unit unit, double increment) { + private JSTemporalPrecisionRecord(Object precision, Unit unit, int increment) { assert isValidPrecision(precision) : precision; this.precision = precision; this.unit = unit; this.increment = increment; } - public static JSTemporalPrecisionRecord create(Object precision, Unit unit, double increment) { + public static JSTemporalPrecisionRecord create(Object precision, Unit unit, int increment) { return new JSTemporalPrecisionRecord(precision, unit, increment); } @@ -69,7 +69,7 @@ public Unit getUnit() { return unit; } - public double getIncrement() { + public int getIncrement() { return increment; } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java index 73d7166e0ac..64dac96e978 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java @@ -309,8 +309,9 @@ public final class TemporalUtil { public static final int HOURS_PER_DAY = 24; public static final int MINUTES_PER_HOUR = 60; public static final int SECONDS_PER_MINUTE = 60; - public static final double MS_PER_DAY = 8.64 * 10_000_000; - public static final double NS_PER_DAY = 8.64 * 10_000_000_000_000D; + public static final int MS_PER_DAY = 86_400_000; // 24 * 60 * 60 * 1000 + public static final double NS_PER_DAY = 8.64e13; // 24 * 60 * 60 * 1000 * 1000 * 1000 + public static final long NS_PER_DAY_LONG = (long) NS_PER_DAY; public static final int SINCE = -1; public static final int UNTIL = 1; @@ -472,7 +473,7 @@ private static Map createUnitMapping(List si return Map.copyOf(map); } - public static double validateTemporalRoundingIncrement(double increment, double dividend, boolean inclusive, + public static int validateTemporalRoundingIncrement(int increment, long dividend, boolean inclusive, Node node, InlinedBranchProfile errorBranch) { double maximum; if (inclusive) { @@ -499,9 +500,9 @@ public static JSTemporalPrecisionRecord toSecondsStringPrecisionRecord(Unit smal case EMPTY -> switch (fractionalDigitCount) { case ToFractionalSecondDigitsNode.AUTO -> JSTemporalPrecisionRecord.create(AUTO, Unit.NANOSECOND, 1); case 0 -> JSTemporalPrecisionRecord.create(0, Unit.SECOND, 1); - case 1, 2, 3 -> JSTemporalPrecisionRecord.create(fractionalDigitCount, Unit.MILLISECOND, Math.pow(10, 3 - fractionalDigitCount)); - case 4, 5, 6 -> JSTemporalPrecisionRecord.create(fractionalDigitCount, Unit.MICROSECOND, Math.pow(10, 6 - fractionalDigitCount)); - case 7, 8, 9 -> JSTemporalPrecisionRecord.create(fractionalDigitCount, Unit.NANOSECOND, Math.pow(10, 9 - fractionalDigitCount)); + case 1, 2, 3 -> JSTemporalPrecisionRecord.create(fractionalDigitCount, Unit.MILLISECOND, (int) Math.pow(10, 3 - fractionalDigitCount)); + case 4, 5, 6 -> JSTemporalPrecisionRecord.create(fractionalDigitCount, Unit.MICROSECOND, (int) Math.pow(10, 6 - fractionalDigitCount)); + case 7, 8, 9 -> JSTemporalPrecisionRecord.create(fractionalDigitCount, Unit.NANOSECOND, (int) Math.pow(10, 9 - fractionalDigitCount)); default -> throw Errors.shouldNotReachHereUnexpectedValue(fractionalDigitCount); }; default -> throw Errors.shouldNotReachHereUnexpectedValue(smallestUnit); @@ -610,18 +611,18 @@ public static void validateTemporalUnitRange(Unit largestUnit, Unit smallestUnit } } - public static Double maximumTemporalDurationRoundingIncrement(Unit unit) { + public static Integer maximumTemporalDurationRoundingIncrement(Unit unit) { if (unit == Unit.YEAR || unit == Unit.MONTH || unit == Unit.WEEK || unit == Unit.DAY) { return null; // Undefined according to spec, we fix at consumer } if (unit == Unit.HOUR) { - return 24d; + return 24; } if (unit == Unit.MINUTE || unit == Unit.SECOND) { - return 60d; + return 60; } assert unit == Unit.MILLISECOND || unit == Unit.MICROSECOND || unit == Unit.NANOSECOND; - return 1000d; + return 1000; } // 13.32 @@ -1428,8 +1429,7 @@ public static Object toCalendarObject(Object calendarSlotValue) { } @TruffleBoundary - public static BigInt roundTemporalInstant(BigInt ns, double increment, Unit unit, RoundingMode roundingMode) { - assert JSRuntime.isIntegralNumber(increment) : increment; + public static BigInt roundTemporalInstant(BigInt ns, int increment, Unit unit, RoundingMode roundingMode) { BigDecimal incrementNs = BigDecimal.valueOf(increment); if (Unit.HOUR == unit) { incrementNs = incrementNs.multiply(BigDecimal.valueOf(3_600_000_000_000L)); @@ -2363,7 +2363,7 @@ public static AddDaysToZonedDateTimeResult addDaysToZonedDateTime(JSContext ctx, // TODO doing some long arithmetics here. Might need double/BigInteger public static JSTemporalDurationRecord adjustRoundedDurationDays(JSContext ctx, JSRealm realm, TemporalDurationAddNode durationAddNode, TemporalRoundDurationNode roundDurationNode, double years, - double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds, double increment, + double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds, int increment, Unit unit, RoundingMode roundingMode, JSTemporalZonedDateTimeObject zonedRelativeTo, CalendarMethodsRecord calendarRec, TimeZoneMethodsRecord timeZoneRec, JSTemporalPlainDateTimeObject precalculatedPlainDateTime) { if (zonedRelativeTo == null || @@ -2436,7 +2436,7 @@ public static TimeDurationRecord differenceTime(int h1, int min1, int s1, int ms @TruffleBoundary public static TimeRecord roundTime(int hours, int minutes, int seconds, int milliseconds, int microseconds, - int nanoseconds, double increment, Unit unit, RoundingMode roundingMode, Long dayLengthNsParam) { + int nanoseconds, int increment, Unit unit, RoundingMode roundingMode, Long dayLengthNsParam) { double fractionalSecond = ((double) nanoseconds / 1_000_000_000) + ((double) microseconds / 1_000_000) + ((double) milliseconds / 1_000) + seconds; double quantity; @@ -2588,7 +2588,7 @@ public static TimeRecord addTimeDouble(int hour, int minute, int second, int mil @TruffleBoundary public static JSTemporalDurationRecord roundISODateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond, - int nanosecond, double increment, Unit unit, RoundingMode roundingMode, Long dayLength) { + int nanosecond, int increment, Unit unit, RoundingMode roundingMode, Long dayLength) { TimeRecord rt = roundTime(hour, minute, second, millisecond, microsecond, nanosecond, increment, unit, roundingMode, dayLength); ISODateRecord br = balanceISODate(year, month, day + dtoi(rt.days())); return JSTemporalDurationRecord.create(br.year(), br.month(), br.day(), @@ -2790,7 +2790,7 @@ public static BigInt addInstant(BigInt epochNanoseconds, long hours, long minute } @TruffleBoundary - public static TimeDurationRecord differenceInstant(BigInt ns1, BigInt ns2, double roundingIncrement, Unit smallestUnit, Unit largestUnit, RoundingMode roundingMode, + public static TimeDurationRecord differenceInstant(BigInt ns1, BigInt ns2, int roundingIncrement, Unit smallestUnit, Unit largestUnit, RoundingMode roundingMode, TemporalRoundDurationNode roundDuration) { BigInteger difference = ns2.subtract(ns1).bigIntegerValue(); int nanoseconds = difference.remainder(BI_1000).intValue(); @@ -3016,15 +3016,15 @@ public static JSTemporalDateTimeRecord parseTemporalYearMonthString(TruffleStrin @TruffleBoundary public static TruffleString temporalZonedDateTimeToString(JSContext ctx, JSRealm realm, JSDynamicObject zonedDateTimeParam, Object precision, ShowCalendar showCalendar, TruffleString showTimeZone, - TruffleString showOffset, Double incrementParam, Unit unitParam, RoundingMode roundingModeParam) { + TruffleString showOffset, Integer incrementParam, Unit unitParam, RoundingMode roundingModeParam) { assert isTemporalZonedDateTime(zonedDateTimeParam); assert unitParam != null && roundingModeParam != null; JSTemporalZonedDateTimeObject zonedDateTime = (JSTemporalZonedDateTimeObject) zonedDateTimeParam; - double increment = incrementParam == null ? 1 : (double) incrementParam; + int increment = incrementParam == null ? 1 : incrementParam; Unit unit = unitParam == Unit.EMPTY ? Unit.NANOSECOND : unitParam; RoundingMode roundingMode = roundingModeParam == RoundingMode.EMPTY ? RoundingMode.TRUNC : roundingModeParam; - BigInt ns = roundTemporalInstant(zonedDateTime.getNanoseconds(), (long) increment, unit, roundingMode); + BigInt ns = roundTemporalInstant(zonedDateTime.getNanoseconds(), increment, unit, roundingMode); Object timeZone = zonedDateTime.getTimeZone(); JSTemporalInstantObject instant = JSTemporalInstant.create(ctx, realm, ns); JSTemporalCalendarObject isoCalendar = getISO8601Calendar(ctx, realm); From 6233048bee5cdab9389b170b33140cf4af1f7ed6 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 7 Jun 2024 21:06:43 +0000 Subject: [PATCH 013/265] Update graal import. --- graal-js/mx.graal-js/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/mx.graal-js/suite.py b/graal-js/mx.graal-js/suite.py index 5ecc7ddf9a4..c7cc9f11fa5 100644 --- a/graal-js/mx.graal-js/suite.py +++ b/graal-js/mx.graal-js/suite.py @@ -24,7 +24,7 @@ { "name" : "regex", "subdir" : True, - "version" : "a80221fd7d7534c0d2df496f3ec5dba12fd0f8b3", + "version" : "11f7b2aa55277324decc1377ca06eb61443c4d23", "urls" : [ {"url" : "https://github.com/oracle/graal.git", "kind" : "git"}, ] From ca828545334391e1c4169102ea9fa589d6db987b Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 7 Jun 2024 21:06:43 +0000 Subject: [PATCH 014/265] Sync CI files. --- common.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/common.json b/common.json index d9be53f62d0..d811baf1cf2 100644 --- a/common.json +++ b/common.json @@ -8,7 +8,7 @@ "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { - "galahad-jdk": {"name": "jpg-jdk", "version": "23", "build_id": "jdk-23+20-1618", "platformspecific": true, "extrabundles": ["static-libs"]}, + "galahad-jdk": {"name": "jpg-jdk", "version": "23", "build_id": "jdk-23+25-2038", "platformspecific": true, "extrabundles": ["static-libs"]}, "oraclejdk11": {"name": "jpg-jdk", "version": "11.0.11", "build_id": "jdk-11.0.11+9", "platformspecific": true, "extrabundles": ["static-libs"] }, @@ -45,13 +45,13 @@ "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.2+13-jvmci-23.1-b33-sulong", "platformspecific": true }, "graalvm-ee-21": {"name": "graalvm-java21", "version": "23.1.3", "platformspecific": true }, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "23", "build_id": "jdk-23+24", "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+24-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+24-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+24-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+24-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+24-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+24-jvmci-b01-sulong", "platformspecific": true } + "oraclejdk-latest": {"name": "jpg-jdk", "version": "23", "build_id": "jdk-23+25", "platformspecific": true, "extrabundles": ["static-libs"]}, + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+25-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+25-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+25-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+25-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+25-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+25-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { From 6b876d9c52ed6ead4f8dfc425befedf74139cd6a Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 16 May 2024 19:35:27 +0200 Subject: [PATCH 015/265] [GR-54085] Implement asinh, acosh, and atanh using MathUtils. --- .../truffle/js/builtins/math/AcoshNode.java | 13 ++++---- .../truffle/js/builtins/math/AsinhNode.java | 31 ++++--------------- .../truffle/js/builtins/math/AtanhNode.java | 13 +++----- 3 files changed, 18 insertions(+), 39 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/math/AcoshNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/math/AcoshNode.java index 632e0b46b06..91dbb4b54d7 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/math/AcoshNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/math/AcoshNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,6 +41,7 @@ package com.oracle.truffle.js.builtins.math; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.utilities.MathUtils; import com.oracle.truffle.js.nodes.function.JSBuiltin; import com.oracle.truffle.js.runtime.JSContext; @@ -51,12 +52,12 @@ public AcoshNode(JSContext context, JSBuiltin builtin) { } @Specialization - protected static double acoshDouble(double x) { - return Math.log(x + Math.sqrt(x * x - 1)); + protected static double acosh(double x) { + return MathUtils.acosh(x); } - @Specialization - protected double acoshGeneric(Object a) { - return acoshDouble(toDouble(a)); + @Specialization(replaces = "acosh") + protected final double acoshGeneric(Object a) { + return acosh(toDouble(a)); } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/math/AsinhNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/math/AsinhNode.java index 6cb327f058d..65d7db8a010 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/math/AsinhNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/math/AsinhNode.java @@ -40,13 +40,10 @@ */ package com.oracle.truffle.js.builtins.math; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Cached.Shared; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.profiles.InlinedConditionProfile; +import com.oracle.truffle.api.utilities.MathUtils; import com.oracle.truffle.js.nodes.function.JSBuiltin; import com.oracle.truffle.js.runtime.JSContext; -import com.oracle.truffle.js.runtime.JSRuntime; public abstract class AsinhNode extends MathOperation { @@ -55,28 +52,12 @@ public AsinhNode(JSContext context, JSBuiltin builtin) { } @Specialization - protected double asinhDouble(double x, - @Cached @Shared InlinedConditionProfile isNegative) { - if (JSRuntime.isNegativeZero(x)) { - return -0.0; - } - if (x < 0 && Double.isInfinite(x)) { - return x; - } - if (isNegative.profile(this, x < 0)) { - return -asinhImpl(-x); - } else { - return asinhImpl(x); - } + protected static double asinh(double x) { + return MathUtils.asinh(x); } - private static double asinhImpl(double x) { - return Math.log(x + Math.sqrt(x * x + 1)); - } - - @Specialization - protected double asinhGeneric(Object a, - @Cached @Shared InlinedConditionProfile isNegative) { - return asinhDouble(toDouble(a), isNegative); + @Specialization(replaces = "asinh") + protected final double asinhGeneric(Object a) { + return asinh(toDouble(a)); } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/math/AtanhNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/math/AtanhNode.java index 84c8b94977e..c1038572fde 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/math/AtanhNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/math/AtanhNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,9 +41,9 @@ package com.oracle.truffle.js.builtins.math; import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.utilities.MathUtils; import com.oracle.truffle.js.nodes.function.JSBuiltin; import com.oracle.truffle.js.runtime.JSContext; -import com.oracle.truffle.js.runtime.JSRuntime; public abstract class AtanhNode extends MathOperation { @@ -53,14 +53,11 @@ public AtanhNode(JSContext context, JSBuiltin builtin) { @Specialization protected static double atanh(double x) { - if (JSRuntime.isNegativeZero(x)) { - return -0.0; - } - return Math.log((1 + x) / (1 - x)) / 2; + return MathUtils.atanh(x); } - @Specialization - protected double atanh(Object a) { + @Specialization(replaces = "atanh") + protected final double atanhGeneric(Object a) { return atanh(toDouble(a)); } } From 9682f046806b2b003cd7ef628a9893253bb72d7f Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 3 Jun 2024 14:54:31 +0200 Subject: [PATCH 016/265] [GR-54085] Add regression test for asinh, acosh, and atanh. --- .../js/math_asinh_acosh_atanh.js | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 graal-js/src/com.oracle.truffle.js.test/js/math_asinh_acosh_atanh.js diff --git a/graal-js/src/com.oracle.truffle.js.test/js/math_asinh_acosh_atanh.js b/graal-js/src/com.oracle.truffle.js.test/js/math_asinh_acosh_atanh.js new file mode 100644 index 00000000000..ee81737f561 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/js/math_asinh_acosh_atanh.js @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ + +function assertEquals(msg, expected, actual, delta = 0) { + if (Object.is(actual, expected)) { + return; + } else if (delta !== 0 && Math.abs(actual - expected) <= delta) { + return; + } + throw new Error(`${msg} = actual [${actual}], expected [${expected}]${delta !== 0 ? "\u00b1" + delta : ""}`); +} + +function asinhTest() { + for (const [x, r, delta = 0] of [ + [1e-15, 1e-15], // GR-54085 + [3.7252902984619136e-9, 3.7252902984619136e-9], + [2**-28, 2**-28], + [3.725290298461915e-9, 3.725290298461915e-9], + [1e-5, 9.999999999833334e-6], + [0.5, 0.48121182505960347], + [0.9999999999999999, 0.8813735870195429], + [1.0, 0.881373587019543], + [1.0000000000000002, 0.8813735870195432], + [1.5, 1.1947632172871094], + [1.9999999999999996, 1.44363547517881], + [1.9999999999999998, 1.4436354751788103], + [2.0, 1.4436354751788103], + [2.0000000000000004, 1.4436354751788105], + [5.0, 2.3124383412727525], + [1e5, 12.206072645555174], + [Math.PI, 1.8622957433108482], + [11.548739357257748, Math.PI], + [267.74489404101644, 2 * Math.PI], + [2**28, 20.101268236238415], + [268435456.00000006, 20.101268236238415], // GR-54495 + [2**29, 20.79441541679836], + [2**30, 21.487562597358302], + [1e15, 35.23192357547063], + [1e300, 691.4686750787736], + [2.2250738585072014e-308, 2.2250738585072014e-308], // GR-54085 + [5.244519529722009e+307, 709.2439543619927], // GR-54085 + [1e308, 709.889355822726], + [Number.MAX_VALUE, 710.4758600739439], + [Number.MIN_VALUE, Number.MIN_VALUE], + [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY], + [Number.NaN, Number.NaN], + ]) { + assertEquals("asinh(" + x + ")", r, Math.asinh(x), delta); + assertEquals("asinh(" + -x + ")", -r, Math.asinh(-x), delta); + } +} + +function acoshTest() { + for (const [x, r, delta = 0] of [ + // x < 1 := NaN + [0.9999999999999999, Number.NaN], + [2**-28, Number.NaN], + [1e-15, Number.NaN], + [Number.MIN_VALUE, Number.MIN_VALUE], + // x >= 1 + [1.0, 0.0], + [1.0000000000000002, 2.1073424255447017e-8], + [1.1, 0.4435682543851154], + [1.5, 0.9624236501192069], + [2.0, 1.3169578969248166], + [5.0, 2.2924316695611777], + [1e5, 12.206072645505174], + [Math.PI, 1.811526272460853], + [11.591953275521519, Math.PI], + [267.7467614837482, 2 * Math.PI], + [2**28, 20.10126823623841], + [268435456.0000002, 20.10126823623841], + [268435456.00000024, 20.101268236238415], + [2**29, 20.79441541679836], + [2**30, 21.487562597358302], + [1e15, 35.23192357547063], + [1.5243074119957227e+267, 615.904907160801], // GR-54085 (127 ** 127) + [1e300, 691.4686750787736], + [2.2250738585072014e-308, 2.2250738585072014e-308], + [5.244519529722009e+307, 709.2439543619927], + [1e308, 709.889355822726], + [Number.MAX_VALUE, 710.4758600739439], + [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY], + [Number.NaN, Number.NaN], + ]) { + assertEquals("acosh(" + x + ")", x >= 1 ? r : Number.NaN, Math.acosh(x), delta); + assertEquals("acosh(" + -x + ")", Number.NaN, Math.acosh(-x), delta); + } +} + +function atanhTest() { + for (const [x, r, delta = 0] of [ + // |x| > 1 := NaN + [1.0000000000000002, Number.NaN], + [Number.POSITIVE_INFINITY, Number.NaN], + // |x| == 1 := +/-inf + [1.0, Number.POSITIVE_INFINITY], + // |x| < 1 + [0.9999999999999999, 18.714973875118524], + [0.9999930253396107, 6.283185307182609], + [0.99627207622075, 3.141592653589798], + [0.9, 1.4722194895832204], + [0.8, 1.0986122886681098], + [0.7, 0.8673005276940531], + [0.6, 0.6931471805599453], + [0.5, 0.5493061443340548], + [0.4, 0.42364893019360184], + [0.3, 0.30951960420311175], + [0.2, 0.2027325540540822], + [0.1, 0.10033534773107558], + [1e-5, 1.0000000000333335e-5], + [1e-15, 1e-15], // GR-54085 + [0.0, 0.0], + [3.7252902984619136e-9, 3.7252902984619136e-9], + [2**-28, 2**-28], + [3.725290298461915e-9, 3.725290298461915e-9], + [2**-29, 2**-29], + [Number.MIN_VALUE, Number.MIN_VALUE], + [Number.NaN, Number.NaN], + ]) { + assertEquals("atanh(" + x + ")", r, Math.atanh(x), delta); + assertEquals("atanh(" + -x + ")", -r, Math.atanh(-x), delta); + } +} + +asinhTest(); +acoshTest(); +atanhTest(); From 36082a7a688a6a14d0b3322bf917d5f8387b627f Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Fri, 7 Jun 2024 17:22:47 +0200 Subject: [PATCH 017/265] Update test262. --- graal-js/mx.graal-js/mx_graal_js.py | 2 +- .../external/test262/Test262Runnable.java | 1 + graal-js/test/test262.json | 92 ++++++++++++------- 3 files changed, 62 insertions(+), 33 deletions(-) diff --git a/graal-js/mx.graal-js/mx_graal_js.py b/graal-js/mx.graal-js/mx_graal_js.py index 2d753a73578..76a7c2a6030 100644 --- a/graal-js/mx.graal-js/mx_graal_js.py +++ b/graal-js/mx.graal-js/mx_graal_js.py @@ -47,7 +47,7 @@ TEST262_REPO = "https://" + "github.com/tc39/test262.git" # Git revision of Test262 to checkout -TEST262_REV = "007b333af22d8b8466be3394b9248345ac4445c9" +TEST262_REV = "a15874163e6a4f19ee7cd3e47592af382af0f5fd" # Git repository of V8 TESTV8_REPO = "https://" + "github.com/v8/v8.git" diff --git a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java index e98b51427ce..08f0f3793de 100644 --- a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java +++ b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java @@ -265,6 +265,7 @@ public class Test262Runnable extends TestRunnable { "Intl.DurationFormat", "IsHTMLDDA", "explicit-resource-management", + "promise-try", "regexp-modifiers", "tail-call-optimization", }); diff --git a/graal-js/test/test262.json b/graal-js/test/test262.json index 402e4f714cc..323da830024 100644 --- a/graal-js/test/test262.json +++ b/graal-js/test/test262.json @@ -1934,14 +1934,30 @@ "filePath" : "built-ins/Temporal/Duration/prototype/add/relativeto-sub-minute-offset.js", "status" : "FAIL", "comment" : "Temporal failures" + }, { + "filePath" : "built-ins/Temporal/Duration/prototype/round/calendar-dateadd-called-with-options-undefined.js", + "status" : "FAIL", + "comment" : "new failures 2024-06-07" }, { "filePath" : "built-ins/Temporal/Duration/prototype/round/calendar-dateuntil-called-with-singular-largestunit.js", "status" : "FAIL", "comment" : "new failures 2023-05-16" + }, { + "filePath" : "built-ins/Temporal/Duration/prototype/round/dateuntil-field.js", + "status" : "FAIL", + "comment" : "new failures 2024-06-07" + }, { + "filePath" : "built-ins/Temporal/Duration/prototype/round/dst-balancing-result.js", + "status" : "FAIL", + "comment" : "new failures 2024-06-07" }, { "filePath" : "built-ins/Temporal/Duration/prototype/round/dst-rounding-result.js", "status" : "FAIL", "comment" : "new failures 2024-04-12" + }, { + "filePath" : "built-ins/Temporal/Duration/prototype/round/largestunit-smallestunit-combinations-relativeto.js", + "status" : "FAIL", + "comment" : "new failures 2024-06-07" }, { "filePath" : "built-ins/Temporal/Duration/prototype/round/largestunit-smallestunit-default.js", "status" : "FAIL", @@ -2027,9 +2043,9 @@ "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/throws-in-unbalance-duration-relative-when-sign-mismatched.js", + "filePath" : "built-ins/Temporal/Duration/prototype/round/timezone-getpossibleinstantsfor-iterable.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-06-07" }, { "filePath" : "built-ins/Temporal/Duration/prototype/round/total-duration-nanoseconds-too-large-with-zoned-datetime.js", "status" : "FAIL", @@ -2086,6 +2102,18 @@ "filePath" : "built-ins/Temporal/Duration/prototype/total/balance-negative-result.js", "status" : "FAIL", "comment" : "Temporal failures" + }, { + "filePath" : "built-ins/Temporal/Duration/prototype/total/calendar-dateuntil-called-with-singular-largestunit.js", + "status" : "FAIL", + "comment" : "new failures 2024-06-07" + }, { + "filePath" : "built-ins/Temporal/Duration/prototype/total/dst-balancing-result.js", + "status" : "FAIL", + "comment" : "new failures 2024-06-07" + }, { + "filePath" : "built-ins/Temporal/Duration/prototype/total/dst-day-length.js", + "status" : "FAIL", + "comment" : "new failures 2024-06-07" }, { "filePath" : "built-ins/Temporal/Duration/prototype/total/dst-rounding-result.js", "status" : "FAIL", @@ -2150,6 +2178,14 @@ "filePath" : "built-ins/Temporal/Duration/prototype/total/relativeto-zoneddatetime-with-fractional-days.js", "status" : "FAIL", "comment" : "new failures 2022-08-08" + }, { + "filePath" : "built-ins/Temporal/Duration/prototype/total/total-of-each-unit-relativeto.js", + "status" : "FAIL", + "comment" : "new failures 2024-06-07" + }, { + "filePath" : "built-ins/Temporal/Duration/prototype/total/total-of-each-unit.js", + "status" : "FAIL", + "comment" : "new failures 2024-06-07" }, { "filePath" : "built-ins/Temporal/Instant/compare/argument-string-date-with-utc-offset.js", "status" : "FAIL", @@ -3439,13 +3475,13 @@ "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/calendar-dateadd-called-with-options-undefined.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-06-07" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/date-and-time-durations-opposite-signs.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js", "status" : "FAIL", - "comment" : "new failures 2024-03-15" + "comment" : "new failures 2023-10-09" }, { "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/dst-month-day-boundary.js", "status" : "FAIL", @@ -3458,14 +3494,6 @@ "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/find-intermediate-instant.js", "status" : "FAIL", "comment" : "new failures 2024-04-12" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/normalized-time-duration-to-days-loop-arbitrarily.js", - "status" : "FAIL", - "comment" : "new failures 2024-04-12" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/normalized-time-duration-to-days-range-errors.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" }, { "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/order-of-operations.js", "status" : "FAIL", @@ -3475,9 +3503,9 @@ "status" : "FAIL", "comment" : "new failures 2023-11-30" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/roundingincrement-non-integer.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/roundingincrement-addition-out-of-range.js", "status" : "FAIL", - "comment" : "new failures 2023-02-13" + "comment" : "new failures 2024-06-07" }, { "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/roundingmode-ceil.js", "status" : "FAIL", @@ -3527,13 +3555,13 @@ "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/calendar-dateadd-called-with-options-undefined.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-06-07" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/date-and-time-durations-opposite-signs.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js", "status" : "FAIL", - "comment" : "new failures 2024-03-15" + "comment" : "new failures 2023-10-09" }, { "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/dst-month-day-boundary.js", "status" : "FAIL", @@ -3546,14 +3574,6 @@ "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/find-intermediate-instant.js", "status" : "FAIL", "comment" : "new failures 2024-04-12" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/normalized-time-duration-to-days-loop-arbitrarily.js", - "status" : "FAIL", - "comment" : "new failures 2024-04-12" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/normalized-time-duration-to-days-range-errors.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" }, { "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/order-of-operations.js", "status" : "FAIL", @@ -3563,9 +3583,9 @@ "status" : "FAIL", "comment" : "new failures 2023-11-30" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/roundingincrement-non-integer.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/roundingincrement-addition-out-of-range.js", "status" : "FAIL", - "comment" : "new failures 2023-02-13" + "comment" : "new failures 2024-06-07" }, { "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/roundingmode-ceil.js", "status" : "FAIL", @@ -4154,9 +4174,17 @@ "status" : "FAIL", "comment" : "new failures 2022-07-13" }, { - "filePath" : "intl402/Temporal/Calendar/prototype/yearMonthFromFields/reference-day.js", + "filePath" : "intl402/Temporal/Calendar/prototype/yearMonthFromFields/reference-day-chinese.js", "status" : "FAIL", - "comment" : "new failures 2023-03-10" + "comment" : "new failures 2024-06-07" + }, { + "filePath" : "intl402/Temporal/Calendar/prototype/yearMonthFromFields/reference-day-gregory.js", + "status" : "FAIL", + "comment" : "new failures 2024-06-07" + }, { + "filePath" : "intl402/Temporal/Calendar/prototype/yearMonthFromFields/reference-day-hebrew.js", + "status" : "FAIL", + "comment" : "new failures 2024-06-07" }, { "filePath" : "intl402/Temporal/Calendar/prototype/yearOfWeek/gregory-iso-weekofyear.js", "status" : "FAIL", From b666d09b80acf8ab9314ce1d7836a26e06c4c8fc Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Fri, 7 Jun 2024 16:17:58 +0200 Subject: [PATCH 018/265] Simplify ToTemporalCalendarObjectNode. --- .../temporal/ToTemporalCalendarObjectNode.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalCalendarObjectNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalCalendarObjectNode.java index 6a47c8f90d8..c7a04ceb8b4 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalCalendarObjectNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalCalendarObjectNode.java @@ -40,12 +40,10 @@ */ package com.oracle.truffle.js.nodes.temporal; -import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.nodes.JavaScriptBaseNode; -import com.oracle.truffle.js.nodes.access.IsObjectNode; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalCalendar; /** @@ -64,12 +62,14 @@ public static ToTemporalCalendarObjectNode create() { public abstract Object execute(Object calendarSlotValue); @Specialization - public Object toTemporalCalendarObject(Object calendarSlotValue, - @Cached IsObjectNode isObjectNode) { - if (isObjectNode.executeBoolean(calendarSlotValue)) { - return calendarSlotValue; + final Object toTemporalCalendarObject(Object calendarSlotValue) { + Object calendar; + if (calendarSlotValue instanceof TruffleString calendarID) { + calendar = JSTemporalCalendar.create(getJSContext(), getRealm(), calendarID); + } else { + calendar = calendarSlotValue; } - return JSTemporalCalendar.create(getJSContext(), getRealm(), (TruffleString) calendarSlotValue); + return calendar; } } From 8216fa35fb94c16e3eaab0ff9dec5a414fea8263 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Fri, 7 Jun 2024 19:15:30 +0200 Subject: [PATCH 019/265] Migrate Temporal rounding and related operations to latest spec. --- .../TemporalCalendarPrototypeBuiltins.java | 9 +- .../TemporalDurationFunctionBuiltins.java | 27 +- .../TemporalDurationPrototypeBuiltins.java | 306 ++++--- .../TemporalInstantPrototypeBuiltins.java | 7 +- .../TemporalPlainDatePrototypeBuiltins.java | 34 +- ...emporalPlainDateTimePrototypeBuiltins.java | 67 +- .../TemporalPlainTimePrototypeBuiltins.java | 22 +- ...mporalPlainYearMonthPrototypeBuiltins.java | 44 +- .../TemporalTimeZonePrototypeBuiltins.java | 5 +- ...emporalZonedDateTimePrototypeBuiltins.java | 39 +- .../temporal/DifferenceISODateTimeNode.java | 111 +++ ...fferencePlainDateTimeWithRoundingNode.java | 109 +++ .../temporal/DifferenceZonedDateTimeNode.java | 142 ++++ ...fferenceZonedDateTimeWithRoundingNode.java | 107 +++ .../temporal/RoundRelativeDurationNode.java | 401 +++++++++ .../nodes/temporal/TemporalAddDateNode.java | 11 +- .../temporal/TemporalAddDateTimeNode.java | 93 +++ .../temporal/TemporalDurationAddNode.java | 159 ---- .../temporal/TemporalRoundDurationNode.java | 413 ---------- ...oralUnbalanceDateDurationRelativeNode.java | 129 +-- .../com/oracle/truffle/js/runtime/BigInt.java | 6 + .../builtins/temporal/ISODateTimeRecord.java | 67 ++ .../temporal/NormalizedDurationRecord.java | 60 ++ ...a => TemporalDurationWithTotalRecord.java} | 12 +- .../truffle/js/runtime/util/TemporalUtil.java | 776 ++++++++++-------- 25 files changed, 1889 insertions(+), 1267 deletions(-) create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/DifferenceISODateTimeNode.java create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/DifferencePlainDateTimeWithRoundingNode.java create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/DifferenceZonedDateTimeNode.java create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/DifferenceZonedDateTimeWithRoundingNode.java create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/RoundRelativeDurationNode.java create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalAddDateTimeNode.java delete mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalDurationAddNode.java delete mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalRoundDurationNode.java create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/ISODateTimeRecord.java create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/NormalizedDurationRecord.java rename graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/{NormalizedTimeDurationToDaysResult.java => TemporalDurationWithTotalRecord.java} (84%) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalCalendarPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalCalendarPrototypeBuiltins.java index 520dfa98006..b4138be6b5b 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalCalendarPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalCalendarPrototypeBuiltins.java @@ -90,6 +90,7 @@ import com.oracle.truffle.js.nodes.temporal.TemporalGetOptionNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalDateNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalDurationNode; +import com.oracle.truffle.js.runtime.BigInt; import com.oracle.truffle.js.runtime.Boundaries; import com.oracle.truffle.js.runtime.Errors; import com.oracle.truffle.js.runtime.JSContext; @@ -437,10 +438,12 @@ protected Object dateAdd(JSTemporalCalendarObject calendar, Object dateObj, Obje JSDynamicObject options = getOptionsObject(optionsParam, this, errorBranch, optionUndefined); Overflow overflow = TemporalUtil.toTemporalOverflow(options, getOptionNode); JSRealm realm = getRealm(); - TimeDurationRecord balanceResult = TemporalUtil.balanceTimeDuration(duration.getDays(), duration.getHours(), duration.getMinutes(), duration.getSeconds(), - duration.getMilliseconds(), duration.getMicroseconds(), duration.getNanoseconds(), Unit.DAY); + BigInt norm = TemporalUtil.normalizeTimeDuration(duration.getHours(), duration.getMinutes(), duration.getSeconds(), + duration.getMilliseconds(), duration.getMicroseconds(), duration.getNanoseconds()); + TimeDurationRecord balanceResult = TemporalUtil.balanceTimeDuration(norm, Unit.DAY); + double days = duration.getDays() + balanceResult.days(); ISODateRecord result = TemporalUtil.addISODate(date.getYear(), date.getMonth(), date.getDay(), - duration.getYears(), duration.getMonths(), duration.getWeeks(), balanceResult.days(), overflow); + duration.getYears(), duration.getMonths(), duration.getWeeks(), days, overflow); return JSTemporalPlainDate.create(getContext(), realm, result.year(), result.month(), result.day(), calendar, this, errorBranch); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationFunctionBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationFunctionBuiltins.java index ec0e73d103e..ad3495a554f 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationFunctionBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationFunctionBuiltins.java @@ -40,8 +40,6 @@ */ package com.oracle.truffle.js.builtins.temporal; -import static com.oracle.truffle.js.runtime.util.TemporalUtil.dtol; - import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.profiles.InlinedBranchProfile; @@ -53,13 +51,13 @@ import com.oracle.truffle.js.nodes.temporal.ToRelativeTemporalObjectNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalDurationNode; import com.oracle.truffle.js.runtime.BigInt; +import com.oracle.truffle.js.runtime.Errors; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRealm; import com.oracle.truffle.js.runtime.builtins.BuiltinEnum; import com.oracle.truffle.js.runtime.builtins.temporal.CalendarMethodsRecord; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDuration; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationObject; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationRecord; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalInstant; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateObject; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateTimeObject; @@ -67,7 +65,6 @@ import com.oracle.truffle.js.runtime.builtins.temporal.TimeZoneMethodsRecord; import com.oracle.truffle.js.runtime.objects.JSDynamicObject; import com.oracle.truffle.js.runtime.util.TemporalUtil; -import com.oracle.truffle.js.runtime.util.TemporalUtil.Unit; public class TemporalDurationFunctionBuiltins extends JSBuiltinsContainer.SwitchEnum { @@ -163,25 +160,27 @@ protected int compare(Object oneParam, Object twoParam, Object optionsParam, if (zonedRelativeTo != null && (calendarUnitsPresent || one.getDays() != 0 || two.getDays() != 0)) { var instant = JSTemporalInstant.create(getContext(), realm, zonedRelativeTo.getNanoseconds()); JSTemporalPlainDateTimeObject precalculatedPlainDateTime = TemporalUtil.builtinTimeZoneGetPlainDateTimeFor(getContext(), realm, timeZoneRec, instant, calendarRec.receiver()); + + BigInt norm1 = TemporalUtil.normalizeTimeDuration(one.getHours(), one.getMinutes(), one.getSeconds(), one.getMilliseconds(), one.getMicroseconds(), one.getNanoseconds()); + BigInt norm2 = TemporalUtil.normalizeTimeDuration(two.getHours(), two.getMinutes(), two.getSeconds(), two.getMilliseconds(), two.getMicroseconds(), two.getNanoseconds()); var after1 = TemporalUtil.addZonedDateTime(getContext(), realm, zonedRelativeTo.getNanoseconds(), timeZoneRec, calendarRec, - dtol(one.getYears()), dtol(one.getMonths()), dtol(one.getWeeks()), dtol(one.getDays()), - dtol(one.getHours()), dtol(one.getMinutes()), dtol(one.getSeconds()), - dtol(one.getMilliseconds()), dtol(one.getMicroseconds()), dtol(one.getNanoseconds()), precalculatedPlainDateTime); + one.getYears(), one.getMonths(), one.getWeeks(), one.getDays(), + norm1, precalculatedPlainDateTime); var after2 = TemporalUtil.addZonedDateTime(getContext(), realm, zonedRelativeTo.getNanoseconds(), timeZoneRec, calendarRec, - dtol(two.getYears()), dtol(two.getMonths()), dtol(two.getWeeks()), dtol(two.getDays()), - dtol(two.getHours()), dtol(two.getMinutes()), dtol(two.getSeconds()), - dtol(two.getMilliseconds()), dtol(two.getMicroseconds()), dtol(two.getNanoseconds()), precalculatedPlainDateTime); + two.getYears(), two.getMonths(), two.getWeeks(), two.getDays(), + norm2, precalculatedPlainDateTime); return after1.compareTo(after2); } double days1; double days2; if (calendarUnitsPresent) { - JSTemporalDurationRecord balanceResult1 = unbalanceDurationRelativeNode.execute(one.getYears(), one.getMonths(), one.getWeeks(), one.getDays(), Unit.DAY, plainRelativeTo, calendarRec); - JSTemporalDurationRecord balanceResult2 = unbalanceDurationRelativeNode.execute(two.getYears(), two.getMonths(), two.getWeeks(), two.getDays(), Unit.DAY, plainRelativeTo, calendarRec); - days1 = balanceResult1.getDays(); - days2 = balanceResult2.getDays(); + if (plainRelativeTo == null) { + throw Errors.createRangeError("A starting point is required for years, months, or weeks comparison"); + } + days1 = unbalanceDurationRelativeNode.execute(one.getYears(), one.getMonths(), one.getWeeks(), one.getDays(), plainRelativeTo, calendarRec); + days2 = unbalanceDurationRelativeNode.execute(two.getYears(), two.getMonths(), two.getWeeks(), two.getDays(), plainRelativeTo, calendarRec); } else { days1 = one.getDays(); days2 = two.getDays(); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java index 2ba32eb4de6..fa7ff721095 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java @@ -42,6 +42,7 @@ import static com.oracle.truffle.js.runtime.util.TemporalConstants.AUTO; import static com.oracle.truffle.js.runtime.util.TemporalConstants.HALF_EXPAND; +import static com.oracle.truffle.js.runtime.util.TemporalConstants.LARGEST_UNIT; import static com.oracle.truffle.js.runtime.util.TemporalConstants.TRUNC; import static com.oracle.truffle.js.runtime.util.TemporalConstants.UNIT; import static com.oracle.truffle.js.runtime.util.TemporalUtil.dtol; @@ -69,17 +70,19 @@ import com.oracle.truffle.js.nodes.function.JSBuiltin; import com.oracle.truffle.js.nodes.function.JSBuiltinNode; import com.oracle.truffle.js.nodes.temporal.CalendarMethodsRecordLookupNode; +import com.oracle.truffle.js.nodes.temporal.DifferencePlainDateTimeWithRoundingNode; +import com.oracle.truffle.js.nodes.temporal.DifferenceZonedDateTimeWithRoundingNode; +import com.oracle.truffle.js.nodes.temporal.DifferenceZonedDateTimeNode; import com.oracle.truffle.js.nodes.temporal.GetRoundingIncrementOptionNode; import com.oracle.truffle.js.nodes.temporal.GetTemporalUnitNode; -import com.oracle.truffle.js.nodes.temporal.TemporalBalanceDateDurationRelativeNode; -import com.oracle.truffle.js.nodes.temporal.TemporalDurationAddNode; +import com.oracle.truffle.js.nodes.temporal.TemporalAddDateNode; +import com.oracle.truffle.js.nodes.temporal.TemporalDifferenceDateNode; import com.oracle.truffle.js.nodes.temporal.TemporalGetOptionNode; -import com.oracle.truffle.js.nodes.temporal.TemporalRoundDurationNode; -import com.oracle.truffle.js.nodes.temporal.TemporalUnbalanceDateDurationRelativeNode; import com.oracle.truffle.js.nodes.temporal.ToFractionalSecondDigitsNode; import com.oracle.truffle.js.nodes.temporal.ToRelativeTemporalObjectNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalDurationNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalPartialDurationRecordNode; +import com.oracle.truffle.js.runtime.BigInt; import com.oracle.truffle.js.runtime.Errors; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRealm; @@ -88,7 +91,6 @@ import com.oracle.truffle.js.runtime.builtins.BuiltinEnum; import com.oracle.truffle.js.runtime.builtins.JSOrdinary; import com.oracle.truffle.js.runtime.builtins.temporal.CalendarMethodsRecord; -import com.oracle.truffle.js.runtime.builtins.temporal.DateDurationRecord; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDuration; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationObject; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationRecord; @@ -98,9 +100,13 @@ import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateTimeObject; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPrecisionRecord; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalZonedDateTimeObject; +import com.oracle.truffle.js.runtime.builtins.temporal.NormalizedDurationRecord; import com.oracle.truffle.js.runtime.builtins.temporal.TimeDurationRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.TimeRecord; import com.oracle.truffle.js.runtime.builtins.temporal.TimeZoneMethodsRecord; import com.oracle.truffle.js.runtime.objects.JSDynamicObject; +import com.oracle.truffle.js.runtime.objects.JSObject; +import com.oracle.truffle.js.runtime.objects.JSObjectUtil; import com.oracle.truffle.js.runtime.objects.Undefined; import com.oracle.truffle.js.runtime.util.TemporalConstants; import com.oracle.truffle.js.runtime.util.TemporalErrors; @@ -337,33 +343,122 @@ protected JSTemporalDurationAddSubNode(JSContext context, JSBuiltin builtin, int } @Specialization - protected JSTemporalDurationObject addDurationToOrSubtractDurationFromDuration(JSTemporalDurationObject duration, Object other, Object options, + protected JSTemporalDurationObject addDurations(JSTemporalDurationObject duration, Object other, Object options, @Cached ToTemporalDurationNode toTemporalDurationNode, @Cached("createDateAdd()") CalendarMethodsRecordLookupNode lookupDateAdd, @Cached("createDateUntil()") CalendarMethodsRecordLookupNode lookupDateUntil, - @Cached TemporalDurationAddNode durationAddNode, @Cached ToRelativeTemporalObjectNode toRelativeTemporalObjectNode, + @Cached TemporalAddDateNode addDateNode, + @Cached TemporalDifferenceDateNode differenceDateNode, + @Cached DifferenceZonedDateTimeNode differenceZonedDateTimeNode, @Cached InlinedBranchProfile errorBranch, - @Cached InlinedConditionProfile optionUndefined) { + @Cached InlinedConditionProfile optionUndefined, + @Cached InlinedBranchProfile relativeToUndefinedBranch, + @Cached InlinedBranchProfile relativeToPlainDateBranch, + @Cached InlinedBranchProfile relativeToZonedDateTimeBranch) { JSTemporalDurationObject otherDuration = toTemporalDurationNode.execute(other); JSDynamicObject normalizedOptions = getOptionsObject(options, this, errorBranch, optionUndefined); var relativeToRec = toRelativeTemporalObjectNode.execute(normalizedOptions); - var relativeTo = relativeToRec.relativeTo(); + JSTemporalPlainDateObject plainRelativeTo = relativeToRec.plainRelativeTo(); + JSTemporalZonedDateTimeObject zonedRelativeTo = relativeToRec.zonedRelativeTo(); TimeZoneMethodsRecord timeZoneRec = relativeToRec.timeZoneRec(); CalendarMethodsRecord calendarRec = relativeToRec.createCalendarMethodsRecord(lookupDateAdd, lookupDateUntil); - JSTemporalDurationRecord result = durationAddNode.execute(duration.getYears(), duration.getMonths(), - duration.getWeeks(), duration.getDays(), duration.getHours(), duration.getMinutes(), - duration.getSeconds(), duration.getMilliseconds(), duration.getMicroseconds(), - duration.getNanoseconds(), - sign * otherDuration.getYears(), sign * otherDuration.getMonths(), sign * otherDuration.getWeeks(), sign * otherDuration.getDays(), - sign * otherDuration.getHours(), sign * otherDuration.getMinutes(), sign * otherDuration.getSeconds(), - sign * otherDuration.getMilliseconds(), sign * otherDuration.getMicroseconds(), sign * otherDuration.getNanoseconds(), - relativeTo, calendarRec, timeZoneRec, null); - return JSTemporalDuration.createTemporalDuration(getContext(), getRealm(), - result.getYears(), result.getMonths(), result.getWeeks(), result.getDays(), - result.getHours(), result.getMinutes(), result.getSeconds(), result.getMilliseconds(), result.getMicroseconds(), result.getNanoseconds(), this, errorBranch); + JSContext ctx = getJSContext(); + JSRealm realm = getRealm(); + + double y1 = duration.getYears(); + double mon1 = duration.getMonths(); + double w1 = duration.getWeeks(); + double d1 = duration.getDays(); + double h1 = duration.getHours(); + double min1 = duration.getMinutes(); + double s1 = duration.getSeconds(); + double ms1 = duration.getMilliseconds(); + double mus1 = duration.getMicroseconds(); + double ns1 = duration.getNanoseconds(); + double y2 = sign * otherDuration.getYears(); + double mon2 = sign * otherDuration.getMonths(); + double w2 = sign * otherDuration.getWeeks(); + double d2 = sign * otherDuration.getDays(); + double h2 = sign * otherDuration.getHours(); + double min2 = sign * otherDuration.getMinutes(); + double s2 = sign * otherDuration.getSeconds(); + double ms2 = sign * otherDuration.getMilliseconds(); + double mus2 = sign * otherDuration.getMicroseconds(); + double ns2 = sign * otherDuration.getNanoseconds(); + + TemporalUtil.Unit largestUnit1 = TemporalUtil.defaultTemporalLargestUnit(y1, mon1, w1, d1, h1, min1, s1, ms1, mus1); + TemporalUtil.Unit largestUnit2 = TemporalUtil.defaultTemporalLargestUnit(y2, mon2, w2, d2, h2, min2, s2, ms2, mus2); + TemporalUtil.Unit largestUnit = TemporalUtil.largerOfTwoTemporalUnits(largestUnit1, largestUnit2); + BigInt norm1 = TemporalUtil.normalizeTimeDuration(h1, min1, s1, ms1, mus1, ns1); + BigInt norm2 = TemporalUtil.normalizeTimeDuration(h2, min2, s2, ms2, mus2, ns2); + + if (zonedRelativeTo == null && plainRelativeTo == null) { + relativeToUndefinedBranch.enter(this); + if (largestUnit.isCalendarUnit()) { + errorBranch.enter(this); + throw Errors.createRangeError("Largest unit allowed with no relativeTo is 'days'."); + } + BigInt normResult = TemporalUtil.addNormalizedTimeDuration(norm1, norm2); + normResult = TemporalUtil.add24HourDaysToNormalizedTimeDuration(normResult, d1 + d2); + TimeDurationRecord result = TemporalUtil.balanceTimeDuration(normResult, largestUnit); + return JSTemporalDuration.createTemporalDuration(ctx, realm, + 0, 0, 0, result.days(), + result.hours(), result.minutes(), result.seconds(), result.milliseconds(), result.microseconds(), result.nanoseconds(), + this, errorBranch); + } else if (plainRelativeTo != null) { + relativeToPlainDateBranch.enter(this); + JSTemporalDurationObject dateDuration1 = JSTemporalDuration.createTemporalDuration(ctx, realm, y1, mon1, w1, d1, 0, 0, 0, 0, 0, 0, this, errorBranch); + JSTemporalDurationObject dateDuration2 = JSTemporalDuration.createTemporalDuration(ctx, realm, y2, mon2, w2, d2, 0, 0, 0, 0, 0, 0, this, errorBranch); + + JSTemporalPlainDateObject intermediate = addDateNode.execute(calendarRec, plainRelativeTo, dateDuration1, Undefined.instance); + JSTemporalPlainDateObject end = addDateNode.execute(calendarRec, intermediate, dateDuration2, Undefined.instance); + + TemporalUtil.Unit dateLargestUnit = TemporalUtil.largerOfTwoTemporalUnits(TemporalUtil.Unit.DAY, largestUnit); + + JSObject differenceOptions = JSOrdinary.createWithNullPrototype(ctx); + JSObjectUtil.putDataProperty(differenceOptions, LARGEST_UNIT, dateLargestUnit.toTruffleString()); + JSTemporalDurationObject dateDifference = differenceDateNode.execute(calendarRec, plainRelativeTo, end, dateLargestUnit, differenceOptions); + BigInt norm1WithDays = TemporalUtil.add24HourDaysToNormalizedTimeDuration(norm1, dateDifference.getDays()); + BigInt normResult = TemporalUtil.addNormalizedTimeDuration(norm1WithDays, norm2); + TimeDurationRecord result = TemporalUtil.balanceTimeDuration(normResult, largestUnit); + return JSTemporalDuration.createTemporalDuration(ctx, realm, + dateDifference.getYears(), dateDifference.getMonths(), dateDifference.getWeeks(), result.days(), + result.hours(), result.minutes(), result.seconds(), result.milliseconds(), result.microseconds(), result.nanoseconds(), + this, errorBranch); + } else { + assert zonedRelativeTo != null; + relativeToZonedDateTimeBranch.enter(this); + JSTemporalPlainDateTimeObject startDateTime = null; + if (largestUnit.isDateUnit()) { + var relativeToInstant = JSTemporalInstant.create(ctx, realm, zonedRelativeTo.getNanoseconds()); + startDateTime = TemporalUtil.builtinTimeZoneGetPlainDateTimeFor(ctx, realm, timeZoneRec, relativeToInstant, calendarRec.receiver()); + } + BigInt intermediateNs = TemporalUtil.addZonedDateTime(ctx, realm, zonedRelativeTo.getNanoseconds(), timeZoneRec, calendarRec, + y1, mon1, w1, d1, norm1, startDateTime); + BigInt endNs = TemporalUtil.addZonedDateTime(ctx, realm, intermediateNs, timeZoneRec, calendarRec, + y2, mon2, w2, d2, norm2, null); + + if (largestUnit.isTimeUnit()) { + BigInt norm = TemporalUtil.normalizedTimeDurationFromEpochNanosecondsDifference(endNs, zonedRelativeTo.getNanoseconds()); + TimeDurationRecord result = TemporalUtil.balanceTimeDuration(norm, largestUnit); + return JSTemporalDuration.createTemporalDuration(ctx, realm, + 0, 0, 0, 0, result.hours(), result.minutes(), result.seconds(), result.milliseconds(), result.microseconds(), result.nanoseconds(), + this, errorBranch); + } else { + JSObject emptyOptions = JSOrdinary.createWithNullPrototype(ctx); + NormalizedDurationRecord diffResult = differenceZonedDateTimeNode.execute( + zonedRelativeTo.getNanoseconds(), endNs, timeZoneRec, calendarRec, largestUnit, emptyOptions, startDateTime); + TimeDurationRecord timeResult = TemporalUtil.balanceTimeDuration(diffResult.normalizedTimeTotalNanoseconds(), Unit.HOUR); + return JSTemporalDuration.createTemporalDuration(ctx, realm, + diffResult.years(), diffResult.months(), diffResult.weeks(), diffResult.days(), + timeResult.hours(), timeResult.minutes(), timeResult.seconds(), + timeResult.milliseconds(), timeResult.microseconds(), timeResult.nanoseconds(), + this, errorBranch); + } + } } @SuppressWarnings("unused") @@ -384,27 +479,27 @@ protected JSTemporalDurationRound(JSContext context, JSBuiltin builtin) { protected JSTemporalDurationObject round(JSTemporalDurationObject duration, Object roundToParam, @Bind("this") Node node, @Cached TruffleString.EqualNode equalNode, - @Cached TemporalDurationAddNode durationAddNode, @Cached InlinedConditionProfile roundToIsTString, @Cached InlinedConditionProfile relativeToIsZonedDateTime, @Cached ToRelativeTemporalObjectNode toRelativeTemporalObjectNode, - @Cached TemporalRoundDurationNode roundDurationNode, @Cached("createDateAdd()") CalendarMethodsRecordLookupNode lookupDateAdd, @Cached("createDateUntil()") CalendarMethodsRecordLookupNode lookupDateUntil, - @Cached TemporalUnbalanceDateDurationRelativeNode unbalanceDurationRelativeNode, - @Cached TemporalBalanceDateDurationRelativeNode balanceDateDurationRelativeNode, @Cached TemporalGetOptionNode getOptionNode, @Cached GetTemporalUnitNode getLargestUnit, @Cached GetTemporalUnitNode getSmallestUnit, @Cached GetRoundingIncrementOptionNode getRoundingIncrementOption, + @Cached TemporalAddDateNode addDate, + @Cached DifferencePlainDateTimeWithRoundingNode differencePlainDateTimeWithRounding, + @Cached DifferenceZonedDateTimeWithRoundingNode differenceZonedDateTimeWithRounding, @Cached InlinedBranchProfile errorBranch, @Cached InlinedConditionProfile optionUndefined) { if (roundToParam == Undefined.instance) { throw TemporalErrors.createTypeErrorOptionsUndefined(); } JSDynamicObject roundTo; + JSContext ctx = getContext(); if (roundToIsTString.profile(node, Strings.isTString(roundToParam))) { - roundTo = JSOrdinary.createWithNullPrototype(getContext()); + roundTo = JSOrdinary.createWithNullPrototype(ctx); JSRuntime.createDataPropertyOrThrow(roundTo, TemporalConstants.SMALLEST_UNIT, roundToParam); } else { roundTo = getOptionsObject(roundToParam, node, errorBranch, optionUndefined); @@ -458,60 +553,69 @@ protected JSTemporalDurationObject round(JSTemporalDurationObject duration, Obje * be determined without calling a calendar or time zone method that no balancing * will take place. */ - return JSTemporalDuration.createTemporalDuration(getContext(), realm, + return JSTemporalDuration.createTemporalDuration(ctx, realm, duration.getYears(), duration.getMonths(), duration.getWeeks(), duration.getDays(), duration.getHours(), duration.getMinutes(), duration.getSeconds(), duration.getMilliseconds(), duration.getMicroseconds(), duration.getNanoseconds(), this, errorBranch); } JSTemporalPlainDateTimeObject precalculatedPlainDateTime = null; - boolean plainDateTimeOrRelativeToWillBeUsed = !roundingGranularityIsNoop || - largestUnit == Unit.YEAR || largestUnit == Unit.MONTH || largestUnit == Unit.WEEK || largestUnit == Unit.DAY || - calendarUnitsPresent || duration.getDays() != 0; + boolean plainDateTimeOrRelativeToWillBeUsed = largestUnit.isCalendarUnit() || largestUnit == Unit.DAY || calendarUnitsPresent || duration.getDays() != 0; if (zonedRelativeTo != null && plainDateTimeOrRelativeToWillBeUsed) { /* * Note: The above conditions mean that the corresponding Temporal.PlainDateTime or * Temporal.PlainDate for zonedRelativeTo will be used in one of the operations * below. */ - var instant = JSTemporalInstant.create(getContext(), realm, zonedRelativeTo.getNanoseconds()); - precalculatedPlainDateTime = TemporalUtil.builtinTimeZoneGetPlainDateTimeFor(getContext(), getRealm(), + var instant = JSTemporalInstant.create(ctx, realm, zonedRelativeTo.getNanoseconds()); + precalculatedPlainDateTime = TemporalUtil.builtinTimeZoneGetPlainDateTimeFor(ctx, realm, timeZoneRec, instant, zonedRelativeTo.getCalendar()); - plainRelativeTo = JSTemporalPlainDate.create(getContext(), realm, + plainRelativeTo = JSTemporalPlainDate.create(ctx, realm, precalculatedPlainDateTime.getYear(), precalculatedPlainDateTime.getMonth(), precalculatedPlainDateTime.getDay(), zonedRelativeTo.getCalendar(), node, errorBranch); } CalendarMethodsRecord calendarRec = relativeToRec.createCalendarMethodsRecord(lookupDateAdd, lookupDateUntil); - JSTemporalDurationRecord unbalanceResult = unbalanceDurationRelativeNode.execute(duration.getYears(), duration.getMonths(), duration.getWeeks(), duration.getDays(), largestUnit, - plainRelativeTo, calendarRec); - JSTemporalDurationRecord roundResult = roundDurationNode.execute( - unbalanceResult.getYears(), unbalanceResult.getMonths(), unbalanceResult.getWeeks(), unbalanceResult.getDays(), - duration.getHours(), duration.getMinutes(), duration.getSeconds(), duration.getMilliseconds(), - duration.getMicroseconds(), duration.getNanoseconds(), roundingIncrement, smallestUnit, - roundingMode, plainRelativeTo, zonedRelativeTo, calendarRec, timeZoneRec, precalculatedPlainDateTime); - TimeDurationRecord balanceResult; + BigInt norm = TemporalUtil.normalizeTimeDuration(duration.getHours(), duration.getMinutes(), duration.getSeconds(), + duration.getMilliseconds(), duration.getMicroseconds(), duration.getNanoseconds()); + JSObject emptyOptions = JSOrdinary.createWithNullPrototype(ctx); + + JSTemporalDurationRecord roundResult; if (relativeToIsZonedDateTime.profile(node, zonedRelativeTo != null)) { - JSTemporalDurationRecord adjustResult = TemporalUtil.adjustRoundedDurationDays(getContext(), realm, durationAddNode, roundDurationNode, - roundResult.getYears(), roundResult.getMonths(), roundResult.getWeeks(), roundResult.getDays(), - roundResult.getHours(), roundResult.getMinutes(), roundResult.getSeconds(), - roundResult.getMilliseconds(), roundResult.getMicroseconds(), roundResult.getNanoseconds(), - roundingIncrement, smallestUnit, roundingMode, - zonedRelativeTo, calendarRec, timeZoneRec, precalculatedPlainDateTime); - balanceResult = TemporalUtil.balanceTimeDurationRelative(adjustResult.getDays(), adjustResult.getHours(), adjustResult.getMinutes(), adjustResult.getSeconds(), - adjustResult.getMilliseconds(), adjustResult.getMicroseconds(), adjustResult.getNanoseconds(), largestUnit, - zonedRelativeTo, timeZoneRec, precalculatedPlainDateTime, getContext(), realm); + BigInt relativeEpochNs = zonedRelativeTo.getNanoseconds(); + BigInt targetEpochNs = TemporalUtil.addZonedDateTime(ctx, realm, relativeEpochNs, timeZoneRec, calendarRec, + duration.getYears(), duration.getMonths(), duration.getWeeks(), duration.getDays(), + norm, precalculatedPlainDateTime); + + var roundRecord = differenceZonedDateTimeWithRounding.execute(relativeEpochNs, targetEpochNs, calendarRec, timeZoneRec, + precalculatedPlainDateTime, emptyOptions, largestUnit, roundingIncrement, smallestUnit, roundingMode); + roundResult = roundRecord.duration(); + } else if (relativeToIsZonedDateTime.profile(node, plainRelativeTo != null)) { + TimeRecord targetTime = TemporalUtil.addTime(0, 0, 0, 0, 0, 0, norm, node, errorBranch); + var dateDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, + duration.getYears(), duration.getMonths(), duration.getWeeks(), duration.getDays() + targetTime.days(), + 0, 0, 0, 0, 0, 0, node, errorBranch); + JSTemporalPlainDateObject targetDate = addDate.execute(calendarRec, plainRelativeTo, dateDuration, Undefined.instance); + var roundRecord = differencePlainDateTimeWithRounding.execute(plainRelativeTo, 0, 0, 0, 0, 0, 0, + targetDate.getYear(), targetDate.getMonth(), targetDate.getDay(), + targetTime.hour(), targetTime.minute(), targetTime.second(), targetTime.millisecond(), targetTime.microsecond(), targetTime.nanosecond(), + calendarRec, largestUnit, roundingIncrement, smallestUnit, roundingMode, emptyOptions); + roundResult = roundRecord.duration(); } else { - balanceResult = TemporalUtil.balanceTimeDuration(roundResult.getDays(), roundResult.getHours(), roundResult.getMinutes(), roundResult.getSeconds(), - roundResult.getMilliseconds(), roundResult.getMicroseconds(), roundResult.getNanoseconds(), largestUnit); + if (calendarUnitsPresent || largestUnit.isCalendarUnit() || smallestUnit.isCalendarUnit()) { + throw Errors.createRangeError("a starting point is required for years, months, or weeks balancing and rounding"); + } + var roundRecord = TemporalUtil.roundTimeDuration(duration.getDays(), norm, roundingIncrement, smallestUnit, roundingMode); + BigInt normWithDays = TemporalUtil.add24HourDaysToNormalizedTimeDuration(roundRecord.normalizedDuration().normalizedTimeTotalNanoseconds(), roundRecord.normalizedDuration().days()); + TimeDurationRecord balanceResult = TemporalUtil.balanceTimeDuration(normWithDays, largestUnit); + roundResult = JSTemporalDurationRecord.createWeeks(0, 0, 0, balanceResult.days(), + balanceResult.hours(), balanceResult.minutes(), balanceResult.seconds(), + balanceResult.milliseconds(), balanceResult.microseconds(), balanceResult.nanoseconds()); } - DateDurationRecord result = balanceDateDurationRelativeNode.execute( - roundResult.getYears(), roundResult.getMonths(), roundResult.getWeeks(), - balanceResult.days(), largestUnit, smallestUnit, plainRelativeTo, calendarRec); - return JSTemporalDuration.createTemporalDuration(getContext(), realm, - result.years(), result.months(), result.weeks(), result.days(), - balanceResult.hours(), balanceResult.minutes(), balanceResult.seconds(), - balanceResult.milliseconds(), balanceResult.microseconds(), balanceResult.nanoseconds(), node, errorBranch); + return JSTemporalDuration.createTemporalDuration(ctx, realm, + roundResult.getYears(), roundResult.getMonths(), roundResult.getWeeks(), roundResult.getDays(), + roundResult.getHours(), roundResult.getMinutes(), roundResult.getSeconds(), + roundResult.getMilliseconds(), roundResult.getMicroseconds(), roundResult.getNanoseconds(), node, errorBranch); } @SuppressWarnings("unused") @@ -534,9 +638,10 @@ protected final double total(JSTemporalDurationObject duration, Object totalOfPa @Cached ToRelativeTemporalObjectNode toRelativeTemporalObjectNode, @Cached("createDateAdd()") CalendarMethodsRecordLookupNode lookupDateAdd, @Cached("createDateUntil()") CalendarMethodsRecordLookupNode lookupDateUntil, - @Cached TemporalRoundDurationNode roundDurationNode, - @Cached TemporalUnbalanceDateDurationRelativeNode unbalanceDurationRelativeNode, @Cached GetTemporalUnitNode getTemporalUnit, + @Cached TemporalAddDateNode addDate, + @Cached DifferencePlainDateTimeWithRoundingNode differencePlainDateTimeWithRounding, + @Cached DifferenceZonedDateTimeWithRoundingNode differenceZonedDateTimeWithRounding, @Cached InlinedBranchProfile errorBranch, @Cached InlinedConditionProfile optionUndefined) { if (totalOfParam == Undefined.instance) { @@ -567,7 +672,7 @@ protected final double total(JSTemporalDurationObject duration, Object totalOfPa * below. */ var instant = JSTemporalInstant.create(getContext(), realm, zonedRelativeTo.getNanoseconds()); - precalculatedPlainDateTime = TemporalUtil.builtinTimeZoneGetPlainDateTimeFor(getContext(), getRealm(), + precalculatedPlainDateTime = TemporalUtil.builtinTimeZoneGetPlainDateTimeFor(getContext(), realm, timeZoneRec, instant, zonedRelativeTo.getCalendar()); plainRelativeTo = JSTemporalPlainDate.create(getContext(), realm, precalculatedPlainDateTime.getYear(), precalculatedPlainDateTime.getMonth(), precalculatedPlainDateTime.getDay(), @@ -576,46 +681,42 @@ protected final double total(JSTemporalDurationObject duration, Object totalOfPa CalendarMethodsRecord calendarRec = relativeToRec.createCalendarMethodsRecord(lookupDateAdd, lookupDateUntil); - JSTemporalDurationRecord unbalanceResult = unbalanceDurationRelativeNode.execute( - duration.getYears(), duration.getMonths(), duration.getWeeks(), duration.getDays(), unit, plainRelativeTo, calendarRec); - TimeDurationRecord balanceResult; + BigInt norm = TemporalUtil.normalizeTimeDuration(duration.getHours(), duration.getMinutes(), duration.getSeconds(), + duration.getMilliseconds(), duration.getMicroseconds(), duration.getNanoseconds()); + JSObject emptyOptions = JSOrdinary.createWithNullPrototype(getContext()); + + double total; if (zonedRelativeTo != null) { - JSTemporalZonedDateTimeObject intermediate = TemporalUtil.moveRelativeZonedDateTime(getContext(), realm, zonedRelativeTo, calendarRec, timeZoneRec, - dtol(unbalanceResult.getYears()), dtol(unbalanceResult.getMonths()), dtol(unbalanceResult.getWeeks()), 0, precalculatedPlainDateTime); - balanceResult = TemporalUtil.balancePossiblyInfiniteTimeDurationRelative(unbalanceResult.getDays(), - duration.getHours(), duration.getMinutes(), duration.getSeconds(), - duration.getMilliseconds(), duration.getMicroseconds(), duration.getNanoseconds(), - unit, intermediate, timeZoneRec, null, getContext(), realm); + BigInt relativeEpochNs = zonedRelativeTo.getNanoseconds(); + BigInt targetEpochNs = TemporalUtil.addZonedDateTime(getContext(), realm, relativeEpochNs, timeZoneRec, calendarRec, + duration.getYears(), duration.getMonths(), duration.getWeeks(), duration.getDays(), + norm, precalculatedPlainDateTime); + + var roundRecord = differenceZonedDateTimeWithRounding.execute(relativeEpochNs, targetEpochNs, calendarRec, timeZoneRec, + precalculatedPlainDateTime, emptyOptions, unit, 1, unit, RoundingMode.TRUNC); + total = roundRecord.total(); + } else if (plainRelativeTo != null) { + TimeRecord targetTime = TemporalUtil.addTime(0, 0, 0, 0, 0, 0, norm, node, errorBranch); + + var dateDuration = JSTemporalDuration.createTemporalDuration(getContext(), realm, + duration.getYears(), duration.getMonths(), duration.getWeeks(), duration.getDays() + targetTime.days(), + 0, 0, 0, 0, 0, 0, node, errorBranch); + JSTemporalPlainDateObject targetDate = addDate.execute(calendarRec, plainRelativeTo, dateDuration, Undefined.instance); + var roundRecord = differencePlainDateTimeWithRounding.execute(plainRelativeTo, 0, 0, 0, 0, 0, 0, + targetDate.getYear(), targetDate.getMonth(), targetDate.getDay(), + targetTime.hour(), targetTime.minute(), targetTime.second(), targetTime.millisecond(), targetTime.microsecond(), targetTime.nanosecond(), + calendarRec, unit, 1, unit, RoundingMode.TRUNC, emptyOptions); + total = roundRecord.total(); } else { - balanceResult = TemporalUtil.balancePossiblyInfiniteTimeDuration(unbalanceResult.getDays(), - duration.getHours(), duration.getMinutes(), duration.getSeconds(), - duration.getMilliseconds(), duration.getMicroseconds(), duration.getNanoseconds(), unit); + if (duration.getYears() != 0 || duration.getMonths() != 0 || duration.getWeeks() != 0 || unit.isCalendarUnit()) { + throw Errors.createRangeError("a starting point is required for years, months, or weeks total"); + } + BigInt normWithDays = TemporalUtil.add24HourDaysToNormalizedTimeDuration(norm, duration.getDays()); + var roundRecord = TemporalUtil.roundTimeDuration(0, normWithDays, 1, unit, RoundingMode.TRUNC); + total = roundRecord.total(); } - if (balanceResult.isOverflow()) { - return balanceResult.getOverflow(); - } - JSTemporalDurationRecord roundResult = roundDurationNode.execute( - unbalanceResult.getYears(), unbalanceResult.getMonths(), unbalanceResult.getWeeks(), - balanceResult.days(), balanceResult.hours(), balanceResult.minutes(), balanceResult.seconds(), - balanceResult.milliseconds(), balanceResult.microseconds(), balanceResult.nanoseconds(), - 1, unit, RoundingMode.TRUNC, - plainRelativeTo, zonedRelativeTo, calendarRec, timeZoneRec, precalculatedPlainDateTime); - - double whole = switch (unit) { - case YEAR -> roundResult.getYears(); - case MONTH -> roundResult.getMonths(); - case WEEK -> roundResult.getWeeks(); - case DAY -> roundResult.getDays(); - case HOUR -> roundResult.getHours(); - case MINUTE -> roundResult.getMinutes(); - case SECOND -> roundResult.getSeconds(); - case MILLISECOND -> roundResult.getMilliseconds(); - case MICROSECOND -> roundResult.getMicroseconds(); - case NANOSECOND -> roundResult.getNanoseconds(); - default -> throw Errors.shouldNotReachHereUnexpectedValue(unit); - }; - return whole + roundResult.getRemainder(); + return total; } @SuppressWarnings("unused") @@ -659,7 +760,6 @@ protected TruffleString toString(JSTemporalDurationObject duration, Object opt, @Cached ToFractionalSecondDigitsNode toFractionalSecondDigitsNode, @Cached JSNumberToBigIntNode toBigIntNode, @Cached TruffleString.EqualNode equalNode, - @Cached TemporalRoundDurationNode roundDurationNode, @Cached TemporalGetOptionNode getOptionNode, @Cached GetTemporalUnitNode getSmallestUnit, @Cached InlinedBranchProfile errorBranch, @@ -678,13 +778,13 @@ protected TruffleString toString(JSTemporalDurationObject duration, Object opt, JSTemporalDurationRecord result; if (precision.getUnit() != Unit.NANOSECOND || precision.getIncrement() != 1) { + BigInt norm = TemporalUtil.normalizeTimeDuration(duration.getHours(), duration.getMinutes(), duration.getSeconds(), + duration.getMilliseconds(), duration.getMicroseconds(), duration.getNanoseconds()); Unit largestUnit = TemporalUtil.defaultTemporalLargestUnit(duration.getYears(), duration.getMonths(), duration.getWeeks(), duration.getDays(), duration.getHours(), duration.getMinutes(), duration.getSeconds(), duration.getMilliseconds(), duration.getMicroseconds()); - JSTemporalDurationRecord roundRecord = roundDurationNode.execute(0, 0, 0, 0, - duration.getHours(), duration.getMinutes(), duration.getSeconds(), duration.getMilliseconds(), duration.getMicroseconds(), - duration.getNanoseconds(), precision.getIncrement(), precision.getUnit(), roundingMode); - TimeDurationRecord time = TemporalUtil.balanceTimeDuration(0, roundRecord.getHours(), roundRecord.getMinutes(), roundRecord.getSeconds(), roundRecord.getMilliseconds(), - roundRecord.getMicroseconds(), roundRecord.getNanoseconds(), TemporalUtil.largerOfTwoTemporalUnits(largestUnit, Unit.SECOND)); + var roundRecord = TemporalUtil.roundTimeDuration(0, norm, precision.getIncrement(), precision.getUnit(), roundingMode); + norm = roundRecord.normalizedDuration().normalizedTimeTotalNanoseconds(); + var time = TemporalUtil.balanceTimeDuration(norm, TemporalUtil.largerOfTwoTemporalUnits(largestUnit, Unit.SECOND)); result = JSTemporalDurationRecord.createWeeks(duration.getYears(), duration.getMonths(), duration.getWeeks(), duration.getDays() + time.days(), time.hours(), time.minutes(), time.seconds(), time.milliseconds(), time.microseconds(), time.nanoseconds()); } else { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalInstantPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalInstantPrototypeBuiltins.java index 099a2f8b0de..72183342da0 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalInstantPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalInstantPrototypeBuiltins.java @@ -73,7 +73,6 @@ import com.oracle.truffle.js.nodes.temporal.GetTemporalUnitNode; import com.oracle.truffle.js.nodes.temporal.SnapshotOwnPropertiesNode; import com.oracle.truffle.js.nodes.temporal.TemporalGetOptionNode; -import com.oracle.truffle.js.nodes.temporal.TemporalRoundDurationNode; import com.oracle.truffle.js.nodes.temporal.ToFractionalSecondDigitsNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalCalendarSlotValueNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalDurationNode; @@ -266,15 +265,15 @@ protected JSTemporalDurationObject differenceTemporalInstant(JSTemporalInstantOb @Cached SnapshotOwnPropertiesNode snapshotOwnProperties, @Cached ToTemporalInstantNode toTemporalInstantNode, @Cached GetDifferenceSettingsNode getDifferenceSettings, - @Cached TemporalRoundDurationNode roundDurationNode, @Cached InlinedBranchProfile errorBranch, @Cached InlinedConditionProfile optionUndefined) { JSTemporalInstantObject other = toTemporalInstantNode.execute(otherObj); JSDynamicObject resolvedOptions = snapshotOwnProperties.snapshot(getOptionsObject(options, this, errorBranch, optionUndefined), Null.instance); var settings = getDifferenceSettings.execute(sign, resolvedOptions, TemporalUtil.unitMappingTimeOrAuto, TemporalUtil.unitMappingTime, Unit.NANOSECOND, Unit.SECOND); - TimeDurationRecord norm = TemporalUtil.differenceInstant(instant.getNanoseconds(), other.getNanoseconds(), - settings.roundingIncrement(), settings.smallestUnit(), settings.largestUnit(), settings.roundingMode(), roundDurationNode); + var diffRecord = TemporalUtil.differenceInstant(instant.getNanoseconds(), other.getNanoseconds(), + settings.roundingIncrement(), settings.smallestUnit(), settings.roundingMode()); + BigInt norm = diffRecord.normalizedTimeDuration(); TimeDurationRecord result = TemporalUtil.balanceTimeDuration(norm, settings.largestUnit()); JSRealm realm = getRealm(); return JSTemporalDuration.createTemporalDuration(getContext(), realm, 0, 0, 0, 0, diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainDatePrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainDatePrototypeBuiltins.java index 286be6c6a0a..df720d16e0b 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainDatePrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainDatePrototypeBuiltins.java @@ -41,6 +41,7 @@ package com.oracle.truffle.js.builtins.temporal; import static com.oracle.truffle.js.runtime.util.TemporalConstants.CALENDAR; +import static com.oracle.truffle.js.runtime.util.TemporalConstants.LARGEST_UNIT; import static com.oracle.truffle.js.runtime.util.TemporalConstants.TIME_ZONE; import java.util.EnumSet; @@ -68,21 +69,21 @@ import com.oracle.truffle.js.builtins.temporal.TemporalPlainDatePrototypeBuiltinsFactory.JSTemporalPlainDateUntilSinceNodeGen; import com.oracle.truffle.js.builtins.temporal.TemporalPlainDatePrototypeBuiltinsFactory.JSTemporalPlainDateWithCalendarNodeGen; import com.oracle.truffle.js.builtins.temporal.TemporalPlainDatePrototypeBuiltinsFactory.JSTemporalPlainDateWithNodeGen; -import com.oracle.truffle.js.nodes.access.EnumerableOwnPropertyNamesNode; import com.oracle.truffle.js.nodes.function.JSBuiltin; import com.oracle.truffle.js.nodes.function.JSBuiltinNode; import com.oracle.truffle.js.nodes.temporal.CalendarMethodsRecordLookupNode; import com.oracle.truffle.js.nodes.temporal.CreateTimeZoneMethodsRecordNode; import com.oracle.truffle.js.nodes.temporal.GetDifferenceSettingsNode; import com.oracle.truffle.js.nodes.temporal.IsPartialTemporalObjectNode; +import com.oracle.truffle.js.nodes.temporal.RoundRelativeDurationNode; import com.oracle.truffle.js.nodes.temporal.SnapshotOwnPropertiesNode; import com.oracle.truffle.js.nodes.temporal.TemporalAddDateNode; import com.oracle.truffle.js.nodes.temporal.TemporalCalendarDateFromFieldsNode; import com.oracle.truffle.js.nodes.temporal.TemporalCalendarFieldsNode; import com.oracle.truffle.js.nodes.temporal.TemporalCalendarGetterNode; +import com.oracle.truffle.js.nodes.temporal.TemporalDifferenceDateNode; import com.oracle.truffle.js.nodes.temporal.TemporalGetOptionNode; import com.oracle.truffle.js.nodes.temporal.TemporalMonthDayFromFieldsNode; -import com.oracle.truffle.js.nodes.temporal.TemporalRoundDurationNode; import com.oracle.truffle.js.nodes.temporal.TemporalYearMonthFromFieldsNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalCalendarIdentifierNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalCalendarSlotValueNode; @@ -90,15 +91,17 @@ import com.oracle.truffle.js.nodes.temporal.ToTemporalDurationNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalTimeNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalTimeZoneSlotValueNode; +import com.oracle.truffle.js.runtime.BigInt; import com.oracle.truffle.js.runtime.Errors; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRealm; +import com.oracle.truffle.js.runtime.JSRuntime; import com.oracle.truffle.js.runtime.builtins.BuiltinEnum; import com.oracle.truffle.js.runtime.builtins.JSOrdinary; import com.oracle.truffle.js.runtime.builtins.temporal.CalendarMethodsRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.ISODateTimeRecord; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDuration; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationObject; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationRecord; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalInstantObject; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDate; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateObject; @@ -109,6 +112,7 @@ import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainYearMonthObject; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalZonedDateTime; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalZonedDateTimeObject; +import com.oracle.truffle.js.runtime.builtins.temporal.NormalizedDurationRecord; import com.oracle.truffle.js.runtime.objects.JSDynamicObject; import com.oracle.truffle.js.runtime.objects.JSObject; import com.oracle.truffle.js.runtime.objects.Null; @@ -424,11 +428,11 @@ protected JSTemporalDurationObject differenceTemporalPlainDate(JSTemporalPlainDa @Bind("this") Node node, @Cached("createDateAdd()") CalendarMethodsRecordLookupNode lookupDateAdd, @Cached("createDateUntil()") CalendarMethodsRecordLookupNode lookupDateUntil, - @Cached("createKeys(getContext())") EnumerableOwnPropertyNamesNode namesNode, + @Cached TemporalDifferenceDateNode differenceDate, @Cached ToTemporalDateNode toTemporalDate, @Cached SnapshotOwnPropertiesNode snapshotOwnProperties, @Cached ToTemporalCalendarIdentifierNode toCalendarIdentifier, - @Cached TemporalRoundDurationNode roundDurationNode, + @Cached RoundRelativeDurationNode roundRelativeDuration, @Cached GetDifferenceSettingsNode getDifferenceSettings, @Cached InlinedBranchProfile errorBranch, @Cached InlinedConditionProfile optionUndefined) { @@ -438,26 +442,28 @@ protected JSTemporalDurationObject differenceTemporalPlainDate(JSTemporalPlainDa throw TemporalErrors.createRangeErrorIdenticalCalendarExpected(); } - JSDynamicObject resolvedOptions = snapshotOwnProperties.snapshot(getOptionsObject(options, node, errorBranch, optionUndefined), Null.instance); + JSObject resolvedOptions = snapshotOwnProperties.snapshot(getOptionsObject(options, node, errorBranch, optionUndefined), Null.instance); var settings = getDifferenceSettings.execute(sign, resolvedOptions, TemporalUtil.unitMappingDateOrAuto, TemporalUtil.unitMappingDate, Unit.DAY, Unit.DAY); Object dateAddMethod = lookupDateAdd.execute(temporalDate.getCalendar()); Object dateUntilMethod = lookupDateUntil.execute(temporalDate.getCalendar()); CalendarMethodsRecord calendarRec = CalendarMethodsRecord.forDateAddDateUntil(temporalDate.getCalendar(), dateAddMethod, dateUntilMethod); - JSDynamicObject untilOptions = TemporalUtil.mergeLargestUnitOption(getContext(), namesNode, resolvedOptions, settings.largestUnit()); - JSTemporalDurationObject result = TemporalUtil.calendarDateUntil(calendarRec, temporalDate, other, untilOptions); + JSRuntime.createDataPropertyOrThrow(resolvedOptions, LARGEST_UNIT, settings.largestUnit().toTruffleString()); + JSTemporalDurationObject result = differenceDate.execute(calendarRec, temporalDate, other, settings.largestUnit(), resolvedOptions); + NormalizedDurationRecord duration = TemporalUtil.createNormalizedDurationRecord( + result.getYears(), result.getMonths(), result.getWeeks(), result.getDays(), TemporalUtil.zeroTimeDuration()); boolean roundingGranularityIsNoop = settings.smallestUnit() == Unit.DAY && (settings.roundingIncrement() == 1); if (!roundingGranularityIsNoop) { - JSTemporalDurationRecord result2 = roundDurationNode.execute(result.getYears(), result.getMonths(), result.getWeeks(), result.getDays(), 0, 0, 0, 0, - 0, 0, settings.roundingIncrement(), settings.smallestUnit(), settings.roundingMode(), temporalDate, calendarRec); - return JSTemporalDuration.createTemporalDuration(getContext(), getRealm(), - sign * result2.getYears(), sign * result2.getMonths(), sign * result2.getWeeks(), sign * result2.getDays(), - 0, 0, 0, 0, 0, 0, node, errorBranch); + BigInt destEpochNs = TemporalUtil.getUTCEpochNanoseconds(other.getYear(), other.getMonth(), other.getDay(), 0, 0, 0, 0, 0, 0); + var dateTime = new ISODateTimeRecord(temporalDate.getYear(), temporalDate.getMonth(), temporalDate.getDay(), 0, 0, 0, 0, 0, 0); + var roundedDuration = roundRelativeDuration.execute(duration, destEpochNs, dateTime, calendarRec, null, + settings.largestUnit(), settings.roundingIncrement(), settings.smallestUnit(), settings.roundingMode()).duration(); + duration = new NormalizedDurationRecord(roundedDuration.getYears(), roundedDuration.getMonths(), roundedDuration.getWeeks(), roundedDuration.getDays(), BigInt.ZERO); } return JSTemporalDuration.createTemporalDuration(getContext(), getRealm(), - sign * result.getYears(), sign * result.getMonths(), sign * result.getWeeks(), sign * result.getDays(), + sign * duration.years(), sign * duration.months(), sign * duration.weeks(), sign * duration.days(), 0, 0, 0, 0, 0, 0, node, errorBranch); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainDateTimePrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainDateTimePrototypeBuiltins.java index 52c20429f72..d4b1e0174df 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainDateTimePrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainDateTimePrototypeBuiltins.java @@ -79,23 +79,22 @@ import com.oracle.truffle.js.builtins.temporal.TemporalPlainDateTimePrototypeBuiltinsFactory.JSTemporalPlainDateTimeWithPlainDateNodeGen; import com.oracle.truffle.js.builtins.temporal.TemporalPlainDateTimePrototypeBuiltinsFactory.JSTemporalPlainDateTimeWithPlainTimeNodeGen; import com.oracle.truffle.js.nodes.access.CreateDataPropertyNode; -import com.oracle.truffle.js.nodes.access.EnumerableOwnPropertyNamesNode; import com.oracle.truffle.js.nodes.function.JSBuiltin; import com.oracle.truffle.js.nodes.function.JSBuiltinNode; import com.oracle.truffle.js.nodes.temporal.CalendarMethodsRecordLookupNode; import com.oracle.truffle.js.nodes.temporal.CreateTimeZoneMethodsRecordNode; +import com.oracle.truffle.js.nodes.temporal.DifferencePlainDateTimeWithRoundingNode; import com.oracle.truffle.js.nodes.temporal.GetDifferenceSettingsNode; import com.oracle.truffle.js.nodes.temporal.GetRoundingIncrementOptionNode; import com.oracle.truffle.js.nodes.temporal.GetTemporalUnitNode; import com.oracle.truffle.js.nodes.temporal.IsPartialTemporalObjectNode; import com.oracle.truffle.js.nodes.temporal.SnapshotOwnPropertiesNode; -import com.oracle.truffle.js.nodes.temporal.TemporalBalanceDateDurationRelativeNode; +import com.oracle.truffle.js.nodes.temporal.TemporalAddDateTimeNode; import com.oracle.truffle.js.nodes.temporal.TemporalCalendarDateFromFieldsNode; import com.oracle.truffle.js.nodes.temporal.TemporalCalendarFieldsNode; import com.oracle.truffle.js.nodes.temporal.TemporalCalendarGetterNode; import com.oracle.truffle.js.nodes.temporal.TemporalGetOptionNode; import com.oracle.truffle.js.nodes.temporal.TemporalMonthDayFromFieldsNode; -import com.oracle.truffle.js.nodes.temporal.TemporalRoundDurationNode; import com.oracle.truffle.js.nodes.temporal.TemporalYearMonthFromFieldsNode; import com.oracle.truffle.js.nodes.temporal.ToFractionalSecondDigitsNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalCalendarIdentifierNode; @@ -105,6 +104,7 @@ import com.oracle.truffle.js.nodes.temporal.ToTemporalDurationNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalTimeNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalTimeZoneSlotValueNode; +import com.oracle.truffle.js.runtime.BigInt; import com.oracle.truffle.js.runtime.Boundaries; import com.oracle.truffle.js.runtime.Errors; import com.oracle.truffle.js.runtime.JSContext; @@ -392,6 +392,7 @@ final JSTemporalPlainDateTimeObject addDurationToOrSubtractDurationFromPlainDate JSTemporalPlainDateTimeObject dateTime, Object temporalDurationLike, Object optParam, @Cached ToTemporalDurationNode toTemporalDurationNode, @Cached("createDateAdd()") CalendarMethodsRecordLookupNode lookupDateAdd, + @Cached TemporalAddDateTimeNode addDateTime, @Cached InlinedBranchProfile errorBranch, @Cached InlinedConditionProfile optionUndefined) { JSTemporalDurationObject duration = toTemporalDurationNode.execute(temporalDurationLike); @@ -405,16 +406,15 @@ final JSTemporalPlainDateTimeObject addDurationToOrSubtractDurationFromPlainDate Object dateAddMethod = lookupDateAdd.execute(calendar); CalendarMethodsRecord calendarRec = CalendarMethodsRecord.forDateAdd(calendar, dateAddMethod); - JSTemporalDateTimeRecord result = TemporalUtil.addDateTime(getContext(), getRealm(), + BigInt norm = TemporalUtil.normalizeTimeDuration(sign * duration.getHours(), sign * duration.getMinutes(), sign * duration.getSeconds(), + sign * duration.getMilliseconds(), sign * duration.getMicroseconds(), sign * duration.getNanoseconds()); + JSTemporalDateTimeRecord result = addDateTime.execute( dateTime.getYear(), dateTime.getMonth(), dateTime.getDay(), dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond(), dateTime.getMillisecond(), dateTime.getMicrosecond(), dateTime.getNanosecond(), calendarRec, - sign * duration.getYears(), sign * duration.getMonths(), sign * duration.getWeeks(), sign * duration.getDays(), - sign * duration.getHours(), sign * duration.getMinutes(), sign * duration.getSeconds(), - sign * duration.getMilliseconds(), sign * duration.getMicroseconds(), sign * duration.getNanoseconds(), - options, - this, errorBranch); + sign * duration.getYears(), sign * duration.getMonths(), sign * duration.getWeeks(), sign * duration.getDays(), norm, + options); return JSTemporalPlainDateTime.create(getContext(), getRealm(), result.getYear(), result.getMonth(), result.getDay(), result.getHour(), result.getMinute(), result.getSecond(), result.getMillisecond(), result.getMicrosecond(), @@ -442,13 +442,11 @@ protected JSTemporalPlainDateTimeUntilSinceNode(JSContext context, JSBuiltin bui protected JSTemporalDurationObject differenceTemporalPlainDateTime(JSTemporalPlainDateTimeObject dateTime, Object otherObj, Object options, @Bind("this") Node node, @Cached SnapshotOwnPropertiesNode snapshotOwnProperties, - @Cached("createKeys(getContext())") EnumerableOwnPropertyNamesNode namesNode, @Cached ToTemporalDateTimeNode toTemporalDateTime, @Cached ToTemporalCalendarIdentifierNode toCalendarIdentifier, @Cached("createDateAdd()") CalendarMethodsRecordLookupNode lookupDateAdd, @Cached("createDateUntil()") CalendarMethodsRecordLookupNode lookupDateUntil, - @Cached TemporalRoundDurationNode roundDurationNode, - @Cached TemporalBalanceDateDurationRelativeNode balanceDateDurationRelative, + @Cached DifferencePlainDateTimeWithRoundingNode differencePlainDateTimeWithRounding, @Cached GetDifferenceSettingsNode getDifferenceSettings, @Cached InlinedBranchProfile errorBranch, @Cached InlinedConditionProfile optionUndefined) { @@ -459,33 +457,36 @@ protected JSTemporalDurationObject differenceTemporalPlainDateTime(JSTemporalPla throw TemporalErrors.createRangeErrorIdenticalCalendarExpected(); } - JSDynamicObject resolvedOptions = snapshotOwnProperties.snapshot(getOptionsObject(options, node, errorBranch, optionUndefined), Null.instance); + JSContext ctx = getContext(); + JSRealm realm = getRealm(); + JSObject resolvedOptions = snapshotOwnProperties.snapshot(getOptionsObject(options, node, errorBranch, optionUndefined), Null.instance); var settings = getDifferenceSettings.execute(sign, resolvedOptions, TemporalUtil.unitMappingDateTimeOrAuto, TemporalUtil.unitMappingDateTime, Unit.NANOSECOND, Unit.DAY); + boolean datePartsIdentical = dateTime.getYear() == other.getYear() && dateTime.getMonth() == other.getMonth() && dateTime.getDay() == other.getDay(); + if (datePartsIdentical && dateTime.getHour() == other.getHour() && dateTime.getMinute() == other.getMinute() && dateTime.getSecond() == other.getSecond() && + dateTime.getMillisecond() == other.getMillisecond() && dateTime.getMicrosecond() == other.getMicrosecond() && dateTime.getNanosecond() == other.getNanosecond()) { + return JSTemporalDuration.createTemporalDuration(ctx, realm, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, node, errorBranch); + } + + JSTemporalPlainDateObject plainDate = JSTemporalPlainDate.create(ctx, realm, + dateTime.getYear(), dateTime.getMonth(), dateTime.getDay(), calendar, node, errorBranch); + Object dateAddMethod = lookupDateAdd.execute(calendar); Object dateUntilMethod = lookupDateUntil.execute(calendar); var calendarRec = CalendarMethodsRecord.forDateAddDateUntil(calendar, dateAddMethod, dateUntilMethod); - JSRealm realm = getRealm(); - JSTemporalDurationRecord diff = TemporalUtil.differenceISODateTime(getContext(), getRealm(), namesNode, - dateTime.getYear(), dateTime.getMonth(), dateTime.getDay(), dateTime.getHour(), - dateTime.getMinute(), dateTime.getSecond(), dateTime.getMillisecond(), dateTime.getMicrosecond(), dateTime.getNanosecond(), other.getYear(), other.getMonth(), - other.getDay(), other.getHour(), other.getMinute(), other.getSecond(), other.getMillisecond(), other.getMicrosecond(), other.getNanosecond(), calendarRec, - settings.largestUnit(), resolvedOptions); - JSTemporalPlainDateObject plainRelativeTo = JSTemporalPlainDate.create(getContext(), realm, dateTime.getYear(), dateTime.getMonth(), dateTime.getDay(), calendar, node, errorBranch); - JSTemporalDurationRecord roundResult = roundDurationNode.execute(diff.getYears(), diff.getMonths(), diff.getWeeks(), diff.getDays(), diff.getHours(), - diff.getMinutes(), diff.getSeconds(), diff.getMilliseconds(), diff.getMicroseconds(), diff.getNanoseconds(), - settings.roundingIncrement(), settings.smallestUnit(), settings.roundingMode(), plainRelativeTo, calendarRec); - var result = TemporalUtil.balanceTimeDuration(roundResult.getDays(), roundResult.getHours(), roundResult.getMinutes(), roundResult.getSeconds(), - roundResult.getMilliseconds(), roundResult.getMicroseconds(), roundResult.getNanoseconds(), settings.largestUnit()); - var balanceResult = balanceDateDurationRelative.execute( - roundResult.getYears(), roundResult.getMonths(), roundResult.getWeeks(), result.days(), - settings.largestUnit(), settings.smallestUnit(), plainRelativeTo, calendarRec); - - return JSTemporalDuration.createTemporalDuration(getContext(), realm, - sign * balanceResult.years(), sign * balanceResult.months(), sign * balanceResult.weeks(), sign * balanceResult.days(), - sign * result.hours(), sign * result.minutes(), sign * result.seconds(), - sign * result.milliseconds(), sign * result.microseconds(), sign * result.nanoseconds(), + var resultRecord = differencePlainDateTimeWithRounding.execute(plainDate, + dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond(), dateTime.getMillisecond(), dateTime.getMicrosecond(), dateTime.getNanosecond(), + other.getYear(), other.getMonth(), other.getDay(), + other.getHour(), other.getMinute(), other.getSecond(), other.getMillisecond(), other.getMicrosecond(), other.getNanosecond(), + calendarRec, settings.largestUnit(), settings.roundingIncrement(), settings.smallestUnit(), settings.roundingMode(), resolvedOptions); + JSTemporalDurationRecord result = resultRecord.duration(); + + return JSTemporalDuration.createTemporalDuration(ctx, realm, + sign * result.getYears(), sign * result.getMonths(), sign * result.getWeeks(), sign * result.getDays(), + sign * result.getHours(), sign * result.getMinutes(), sign * result.getSeconds(), + sign * result.getMilliseconds(), sign * result.getMicroseconds(), sign * result.getNanoseconds(), node, errorBranch); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainTimePrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainTimePrototypeBuiltins.java index 3c1053169ed..76916daa223 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainTimePrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainTimePrototypeBuiltins.java @@ -80,12 +80,12 @@ import com.oracle.truffle.js.nodes.temporal.IsPartialTemporalObjectNode; import com.oracle.truffle.js.nodes.temporal.SnapshotOwnPropertiesNode; import com.oracle.truffle.js.nodes.temporal.TemporalGetOptionNode; -import com.oracle.truffle.js.nodes.temporal.TemporalRoundDurationNode; import com.oracle.truffle.js.nodes.temporal.ToFractionalSecondDigitsNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalDateNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalDurationNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalTimeNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalTimeZoneSlotValueNode; +import com.oracle.truffle.js.runtime.BigInt; import com.oracle.truffle.js.runtime.Errors; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRealm; @@ -372,7 +372,6 @@ protected JSTemporalPlainTimeUntilSinceNode(JSContext context, JSBuiltin builtin public JSTemporalDurationObject differenceTemporalPlainTime(JSTemporalPlainTimeObject temporalTime, Object otherObj, Object options, @Cached ToTemporalTimeNode toTemporalTime, @Cached SnapshotOwnPropertiesNode snapshotOwnProperties, - @Cached TemporalRoundDurationNode roundDurationNode, @Cached GetDifferenceSettingsNode getDifferenceSettings, @Cached InlinedBranchProfile errorBranch, @Cached InlinedConditionProfile optionUndefined) { @@ -381,20 +380,21 @@ public JSTemporalDurationObject differenceTemporalPlainTime(JSTemporalPlainTimeO var settings = getDifferenceSettings.execute(sign, resolvedOptions, TemporalUtil.unitMappingTimeOrAuto, TemporalUtil.unitMappingTime, Unit.NANOSECOND, Unit.HOUR); - TimeDurationRecord result = TemporalUtil.differenceTime( + BigInt norm = TemporalUtil.differenceTime( temporalTime.getHour(), temporalTime.getMinute(), temporalTime.getSecond(), temporalTime.getMillisecond(), temporalTime.getMicrosecond(), temporalTime.getNanosecond(), other.getHour(), other.getMinute(), other.getSecond(), other.getMillisecond(), other.getMicrosecond(), other.getNanosecond()); - JSTemporalDurationRecord result2 = roundDurationNode.execute(0, 0, 0, 0, - result.hours(), result.minutes(), result.seconds(), result.milliseconds(), result.microseconds(), - result.nanoseconds(), settings.roundingIncrement(), settings.smallestUnit(), settings.roundingMode()); + + if (settings.smallestUnit() != Unit.NANOSECOND || settings.roundingIncrement() != 1) { + var roundRecord = TemporalUtil.roundTimeDuration(0, norm, settings.roundingIncrement(), settings.smallestUnit(), settings.roundingMode()); + norm = roundRecord.normalizedDuration().normalizedTimeTotalNanoseconds(); + } + JSRealm realm = getRealm(); - TimeDurationRecord result3 = TemporalUtil.balanceTimeDuration( - 0, result2.getHours(), result2.getMinutes(), result2.getSeconds(), result2.getMilliseconds(), result2.getMicroseconds(), - result2.getNanoseconds(), settings.largestUnit()); + TimeDurationRecord result = TemporalUtil.balanceTimeDuration(norm, settings.largestUnit()); return JSTemporalDuration.createTemporalDuration(getContext(), realm, 0, 0, 0, 0, - sign * result3.hours(), sign * result3.minutes(), sign * result3.seconds(), sign * result3.milliseconds(), sign * result3.microseconds(), - sign * result3.nanoseconds(), this, errorBranch); + sign * result.hours(), sign * result.minutes(), sign * result.seconds(), + sign * result.milliseconds(), sign * result.microseconds(), sign * result.nanoseconds(), this, errorBranch); } @SuppressWarnings("unused") diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainYearMonthPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainYearMonthPrototypeBuiltins.java index 361211ba311..c86d9710e79 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainYearMonthPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainYearMonthPrototypeBuiltins.java @@ -73,17 +73,18 @@ import com.oracle.truffle.js.nodes.temporal.CalendarMethodsRecordLookupNode; import com.oracle.truffle.js.nodes.temporal.GetDifferenceSettingsNode; import com.oracle.truffle.js.nodes.temporal.IsPartialTemporalObjectNode; +import com.oracle.truffle.js.nodes.temporal.RoundRelativeDurationNode; import com.oracle.truffle.js.nodes.temporal.SnapshotOwnPropertiesNode; import com.oracle.truffle.js.nodes.temporal.TemporalAddDateNode; import com.oracle.truffle.js.nodes.temporal.TemporalCalendarDateFromFieldsNode; import com.oracle.truffle.js.nodes.temporal.TemporalCalendarFieldsNode; import com.oracle.truffle.js.nodes.temporal.TemporalCalendarGetterNode; import com.oracle.truffle.js.nodes.temporal.TemporalGetOptionNode; -import com.oracle.truffle.js.nodes.temporal.TemporalRoundDurationNode; import com.oracle.truffle.js.nodes.temporal.TemporalYearMonthFromFieldsNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalCalendarIdentifierNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalDurationNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalYearMonthNode; +import com.oracle.truffle.js.runtime.BigInt; import com.oracle.truffle.js.runtime.Errors; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRealm; @@ -91,12 +92,13 @@ import com.oracle.truffle.js.runtime.builtins.BuiltinEnum; import com.oracle.truffle.js.runtime.builtins.JSOrdinary; import com.oracle.truffle.js.runtime.builtins.temporal.CalendarMethodsRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.ISODateTimeRecord; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDuration; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationObject; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationRecord; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateObject; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainYearMonth; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainYearMonthObject; +import com.oracle.truffle.js.runtime.builtins.temporal.NormalizedDurationRecord; import com.oracle.truffle.js.runtime.objects.JSDynamicObject; import com.oracle.truffle.js.runtime.objects.JSObject; import com.oracle.truffle.js.runtime.objects.Null; @@ -470,10 +472,11 @@ protected JSTemporalPlainYearMonthObject addDurationToOrSubtractDurationFromPlai if (operation == TemporalUtil.SUBTRACT) { duration = JSTemporalDuration.createNegatedTemporalDuration(getContext(), realm, duration); } - var balanceResult = TemporalUtil.balanceTimeDuration( - duration.getDays(), duration.getHours(), duration.getMinutes(), duration.getSeconds(), - duration.getMilliseconds(), duration.getMicroseconds(), duration.getNanoseconds(), Unit.DAY); - int sign = TemporalUtil.durationSign(duration.getYears(), duration.getMonths(), duration.getWeeks(), balanceResult.days(), 0, 0, 0, 0, 0, 0); + BigInt norm = TemporalUtil.normalizeTimeDuration(duration.getHours(), duration.getMinutes(), duration.getSeconds(), + duration.getMilliseconds(), duration.getMicroseconds(), duration.getNanoseconds()); + var balanceResult = TemporalUtil.balanceTimeDuration(norm, Unit.DAY); + double days = duration.getDays() + balanceResult.days(); + int sign = TemporalUtil.durationSign(duration.getYears(), duration.getMonths(), duration.getWeeks(), days, 0, 0, 0, 0, 0, 0); Object calendarSlotValue = yearMonth.getCalendar(); Object dateAddMethod = lookupDateAdd.execute(calendarSlotValue); @@ -496,7 +499,7 @@ protected JSTemporalPlainYearMonthObject addDurationToOrSubtractDurationFromPlai TemporalUtil.createDataPropertyOrThrow(getContext(), fields, TemporalConstants.DAY, day); JSTemporalPlainDateObject intermediateDate = dateFromFieldsNode.execute(calendarRec, fields, Undefined.instance); JSTemporalDurationObject durationToAdd = JSTemporalDuration.createTemporalDuration(getContext(), realm, - duration.getYears(), duration.getMonths(), duration.getWeeks(), balanceResult.days(), 0, 0, 0, 0, 0, 0, this, errorBranch); + duration.getYears(), duration.getMonths(), duration.getWeeks(), days, 0, 0, 0, 0, 0, 0, this, errorBranch); JSObject optionsCopy = snapshotOwnProperties.snapshot(options, Null.instance); JSTemporalPlainDateObject addedDate = addDateNode.execute(calendarRec, intermediateDate, durationToAdd, options); JSObject addedDateFields = TemporalUtil.prepareTemporalFields(getContext(), addedDate, fieldNames, TemporalUtil.listEmpty); @@ -523,7 +526,6 @@ protected JSTemporalPlainYearMonthUntilSinceNode(JSContext context, JSBuiltin bu @Specialization protected JSTemporalDurationObject differenceTemporalPlainYearMonth(JSTemporalPlainYearMonthObject thisYearMonth, Object otherParam, Object options, @Bind("this") Node node, - @Cached InlinedConditionProfile unitIsMonth, @Cached ToTemporalCalendarIdentifierNode toCalendarIdentifier, @Cached SnapshotOwnPropertiesNode snapshotOwnProperties, @Cached("createDateAdd()") CalendarMethodsRecordLookupNode lookupDateAdd, @@ -532,7 +534,7 @@ protected JSTemporalDurationObject differenceTemporalPlainYearMonth(JSTemporalPl @Cached("createFields()") CalendarMethodsRecordLookupNode lookupFields, @Cached("createKeys(getContext())") EnumerableOwnPropertyNamesNode namesNode, @Cached GetDifferenceSettingsNode getDifferenceSettings, - @Cached TemporalRoundDurationNode roundDurationNode, + @Cached RoundRelativeDurationNode roundRelativeDuration, @Cached ToTemporalYearMonthNode toTemporalYearMonthNode, @Cached TemporalCalendarFieldsNode calendarFieldsNode, @Cached TemporalCalendarDateFromFieldsNode dateFromFieldsNode, @@ -556,20 +558,26 @@ protected JSTemporalDurationObject differenceTemporalPlainYearMonth(JSTemporalPl List fieldNames = calendarFieldsNode.execute(calendarRec, TemporalUtil.listMCY); JSDynamicObject otherFields = TemporalUtil.prepareTemporalFields(getContext(), other, fieldNames, TemporalUtil.listEmpty); TemporalUtil.createDataPropertyOrThrow(getContext(), otherFields, DAY, 1); - JSDynamicObject otherDate = dateFromFieldsNode.execute(calendarRec, otherFields, Undefined.instance); - JSDynamicObject thisFields = TemporalUtil.prepareTemporalFields(getContext(), thisYearMonth, fieldNames, TemporalUtil.listEmpty); + JSTemporalPlainDateObject otherDate = dateFromFieldsNode.execute(calendarRec, otherFields, Undefined.instance); + JSObject thisFields = TemporalUtil.prepareTemporalFields(getContext(), thisYearMonth, fieldNames, TemporalUtil.listEmpty); TemporalUtil.createDataPropertyOrThrow(getContext(), thisFields, DAY, 1); JSTemporalPlainDateObject thisDate = dateFromFieldsNode.execute(calendarRec, thisFields, Undefined.instance); - JSDynamicObject untilOptions = TemporalUtil.mergeLargestUnitOption(getContext(), namesNode, resolvedOptions, settings.largestUnit()); + JSObject untilOptions = TemporalUtil.mergeLargestUnitOption(getContext(), namesNode, resolvedOptions, settings.largestUnit()); JSTemporalDurationObject result = TemporalUtil.calendarDateUntil(calendarRec, thisDate, otherDate, untilOptions); JSRealm realm = getRealm(); - if (unitIsMonth.profile(node, Unit.MONTH == settings.smallestUnit() && settings.roundingIncrement() == 1)) { - return JSTemporalDuration.createTemporalDuration(getContext(), realm, sign * result.getYears(), sign * result.getMonths(), 0, 0, 0, 0, 0, 0, 0, 0, node, errorBranch); - } else { - JSTemporalDurationRecord result2 = roundDurationNode.execute(result.getYears(), result.getMonths(), 0, 0, 0, 0, 0, 0, 0, 0, settings.roundingIncrement(), - settings.smallestUnit(), settings.roundingMode(), thisDate, calendarRec); - return JSTemporalDuration.createTemporalDuration(getContext(), realm, sign * result2.getYears(), sign * result2.getMonths(), 0, 0, 0, 0, 0, 0, 0, 0, node, errorBranch); + NormalizedDurationRecord duration = TemporalUtil.createNormalizedDurationRecord(result.getYears(), result.getMonths(), 0, 0, TemporalUtil.zeroTimeDuration()); + double durationYears = duration.years(); + double durationMonths = duration.months(); + boolean roundingGranularityIsNoop = settings.smallestUnit() == Unit.MONTH && settings.roundingIncrement() == 1; + if (!roundingGranularityIsNoop) { + BigInt destEpochNs = TemporalUtil.getUTCEpochNanoseconds(otherDate.getYear(), otherDate.getMonth(), otherDate.getDay(), 0, 0, 0, 0, 0, 0); + var dateTime = new ISODateTimeRecord(thisDate.getYear(), thisDate.getMonth(), thisDate.getDay(), 0, 0, 0, 0, 0, 0); + var roundedDuration = roundRelativeDuration.execute(duration, destEpochNs, dateTime, calendarRec, null, + settings.largestUnit(), settings.roundingIncrement(), settings.smallestUnit(), settings.roundingMode()).duration(); + durationYears = roundedDuration.getYears(); + durationMonths = roundedDuration.getMonths(); } + return JSTemporalDuration.createTemporalDuration(getContext(), realm, sign * durationYears, sign * durationMonths, 0, 0, 0, 0, 0, 0, 0, 0, node, errorBranch); } @SuppressWarnings("unused") diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalTimeZonePrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalTimeZonePrototypeBuiltins.java index b161a7e0602..cbd9276411e 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalTimeZonePrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalTimeZonePrototypeBuiltins.java @@ -40,7 +40,6 @@ */ package com.oracle.truffle.js.builtins.temporal; -import java.math.BigInteger; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; @@ -295,9 +294,9 @@ protected JSDynamicObject getPossibleInstantsFor(JSTemporalTimeZoneObject timeZo JSTemporalPlainDateTimeObject dateTime = toTemporalDateTime.execute(dateTimeParam, Undefined.instance); JSRealm realm = getRealm(); if (timeZone.getNanoseconds() != null) { - BigInteger epochNanoseconds = TemporalUtil.getUTCEpochNanoseconds(dateTime.getYear(), dateTime.getMonth(), dateTime.getDay(), dateTime.getHour(), dateTime.getMinute(), + BigInt epochNanoseconds = TemporalUtil.getUTCEpochNanoseconds(dateTime.getYear(), dateTime.getMonth(), dateTime.getDay(), dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond(), dateTime.getMillisecond(), dateTime.getMicrosecond(), dateTime.getNanosecond()); - Object instant = JSTemporalInstant.create(getContext(), realm, new BigInt(epochNanoseconds.subtract(timeZone.getNanoseconds().bigIntegerValue()))); + Object instant = JSTemporalInstant.create(getContext(), realm, epochNanoseconds.subtract(timeZone.getNanoseconds())); List list = new ArrayList<>(); list.add(instant); return JSRuntime.createArrayFromList(getContext(), realm, list); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalZonedDateTimePrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalZonedDateTimePrototypeBuiltins.java index def2a7ef7b5..9c750cfbdfc 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalZonedDateTimePrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalZonedDateTimePrototypeBuiltins.java @@ -84,12 +84,12 @@ import com.oracle.truffle.js.builtins.temporal.TemporalZonedDateTimePrototypeBuiltinsFactory.JSTemporalZonedDateTimeWithPlainTimeNodeGen; import com.oracle.truffle.js.builtins.temporal.TemporalZonedDateTimePrototypeBuiltinsFactory.JSTemporalZonedDateTimeWithTimeZoneNodeGen; import com.oracle.truffle.js.nodes.access.CreateDataPropertyNode; -import com.oracle.truffle.js.nodes.access.EnumerableOwnPropertyNamesNode; import com.oracle.truffle.js.nodes.cast.JSNumberToBigIntNode; import com.oracle.truffle.js.nodes.function.JSBuiltin; import com.oracle.truffle.js.nodes.function.JSBuiltinNode; import com.oracle.truffle.js.nodes.temporal.CalendarMethodsRecordLookupNode; import com.oracle.truffle.js.nodes.temporal.CreateTimeZoneMethodsRecordNode; +import com.oracle.truffle.js.nodes.temporal.DifferenceZonedDateTimeWithRoundingNode; import com.oracle.truffle.js.nodes.temporal.GetDifferenceSettingsNode; import com.oracle.truffle.js.nodes.temporal.GetRoundingIncrementOptionNode; import com.oracle.truffle.js.nodes.temporal.GetTemporalUnitNode; @@ -98,10 +98,8 @@ import com.oracle.truffle.js.nodes.temporal.TemporalCalendarDateFromFieldsNode; import com.oracle.truffle.js.nodes.temporal.TemporalCalendarFieldsNode; import com.oracle.truffle.js.nodes.temporal.TemporalCalendarGetterNode; -import com.oracle.truffle.js.nodes.temporal.TemporalDurationAddNode; import com.oracle.truffle.js.nodes.temporal.TemporalGetOptionNode; import com.oracle.truffle.js.nodes.temporal.TemporalMonthDayFromFieldsNode; -import com.oracle.truffle.js.nodes.temporal.TemporalRoundDurationNode; import com.oracle.truffle.js.nodes.temporal.TemporalYearMonthFromFieldsNode; import com.oracle.truffle.js.nodes.temporal.ToFractionalSecondDigitsNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalCalendarIdentifierNode; @@ -834,16 +832,14 @@ protected JSTemporalZonedDateTimeUntilSinceNode(JSContext context, JSBuiltin bui protected Object differenceTemporalZonedDateTime(JSTemporalZonedDateTimeObject zonedDateTime, Object otherParam, Object options, @Bind("this") Node node, @Cached SnapshotOwnPropertiesNode snapshotOwnProperties, - @Cached("createKeys(getContext())") EnumerableOwnPropertyNamesNode namesNode, @Cached ToTemporalZonedDateTimeNode toTemporalZonedDateTime, @Cached ToTemporalCalendarIdentifierNode toCalendarIdentifier, @Cached ToTemporalTimeZoneIdentifierNode toTimeZoneIdentifier, - @Cached TemporalDurationAddNode durationAddNode, - @Cached TemporalRoundDurationNode roundDurationNode, @Cached GetDifferenceSettingsNode getDifferenceSettings, @Cached CreateTimeZoneMethodsRecordNode createTimeZoneMethodsRecord, @Cached("createDateAdd()") CalendarMethodsRecordLookupNode lookupDateAdd, @Cached("createDateUntil()") CalendarMethodsRecordLookupNode lookupDateUntil, + @Cached DifferenceZonedDateTimeWithRoundingNode differenceZonedDateTimeWithRounding, @Cached InlinedBranchProfile errorBranch, @Cached InlinedConditionProfile optionUndefined) { JSTemporalZonedDateTimeObject other = toTemporalZonedDateTime.execute(otherParam, Undefined.instance); @@ -852,13 +848,15 @@ protected Object differenceTemporalZonedDateTime(JSTemporalZonedDateTimeObject z errorBranch.enter(node); throw TemporalErrors.createRangeErrorIdenticalCalendarExpected(); } - JSDynamicObject resolvedOptions = snapshotOwnProperties.snapshot(getOptionsObject(options, node, errorBranch, optionUndefined), Null.instance); + JSObject resolvedOptions = snapshotOwnProperties.snapshot(getOptionsObject(options, node, errorBranch, optionUndefined), Null.instance); var settings = getDifferenceSettings.execute(sign, resolvedOptions, TemporalUtil.unitMappingDateTimeOrAuto, TemporalUtil.unitMappingDateTime, Unit.NANOSECOND, Unit.HOUR); Unit largestUnit = settings.largestUnit(); JSRealm realm = getRealm(); if (!(Unit.YEAR == largestUnit || Unit.MONTH == largestUnit || Unit.WEEK == largestUnit || Unit.DAY == largestUnit)) { - TimeDurationRecord result = TemporalUtil.differenceInstant(zonedDateTime.getNanoseconds(), other.getNanoseconds(), - settings.roundingIncrement(), settings.smallestUnit(), largestUnit, settings.roundingMode(), roundDurationNode); + var diffRecord = TemporalUtil.differenceInstant(zonedDateTime.getNanoseconds(), other.getNanoseconds(), + settings.roundingIncrement(), settings.smallestUnit(), settings.roundingMode()); + BigInt norm = diffRecord.normalizedTimeDuration(); + TimeDurationRecord result = TemporalUtil.balanceTimeDuration(norm, largestUnit); return JSTemporalDuration.createTemporalDuration(getContext(), realm, 0, 0, 0, 0, sign * result.hours(), sign * result.minutes(), sign * result.seconds(), sign * result.milliseconds(), sign * result.microseconds(), sign * result.nanoseconds(), node, errorBranch); @@ -879,25 +877,10 @@ protected Object differenceTemporalZonedDateTime(JSTemporalZonedDateTimeObject z var instant = JSTemporalInstant.create(getContext(), realm, zonedDateTime.getNanoseconds()); var precalculatedPlainDateTime = TemporalUtil.builtinTimeZoneGetPlainDateTimeFor(getContext(), realm, timeZoneRec, instant, options); - var plainRelativeTo = JSTemporalPlainDate.create(getContext(), realm, - precalculatedPlainDateTime.getYear(), precalculatedPlainDateTime.getMonth(), precalculatedPlainDateTime.getDay(), - calendar, node, errorBranch); - - JSDynamicObject untilOptions = TemporalUtil.mergeLargestUnitOption(getContext(), namesNode, resolvedOptions, largestUnit); - JSTemporalDurationRecord difference = TemporalUtil.differenceZonedDateTime(getContext(), realm, namesNode, - zonedDateTime.getNanoseconds(), other.getNanoseconds(), timeZoneRec, calendarRec, largestUnit, - precalculatedPlainDateTime, untilOptions); - JSTemporalDurationRecord roundResult = roundDurationNode.execute(difference.getYears(), difference.getMonths(), difference.getWeeks(), - difference.getDays(), - difference.getHours(), difference.getMinutes(), difference.getSeconds(), - difference.getMilliseconds(), difference.getMicroseconds(), difference.getNanoseconds(), - settings.roundingIncrement(), settings.smallestUnit(), settings.roundingMode(), - plainRelativeTo, zonedDateTime, calendarRec, timeZoneRec, precalculatedPlainDateTime); - JSTemporalDurationRecord result = TemporalUtil.adjustRoundedDurationDays(getContext(), realm, durationAddNode, roundDurationNode, - roundResult.getYears(), roundResult.getMonths(), roundResult.getWeeks(), roundResult.getDays(), - roundResult.getHours(), roundResult.getMinutes(), roundResult.getSeconds(), - roundResult.getMilliseconds(), roundResult.getMicroseconds(), roundResult.getNanoseconds(), settings.roundingIncrement(), settings.smallestUnit(), settings.roundingMode(), - zonedDateTime, calendarRec, timeZoneRec, precalculatedPlainDateTime); + var resultRecord = differenceZonedDateTimeWithRounding.execute(zonedDateTime.getNanoseconds(), other.getNanoseconds(), calendarRec, timeZoneRec, + precalculatedPlainDateTime, resolvedOptions, largestUnit, settings.roundingIncrement(), settings.smallestUnit(), settings.roundingMode()); + JSTemporalDurationRecord result = resultRecord.duration(); + return JSTemporalDuration.createTemporalDuration(getContext(), realm, sign * result.getYears(), sign * result.getMonths(), sign * result.getWeeks(), sign * result.getDays(), sign * result.getHours(), sign * result.getMinutes(), sign * result.getSeconds(), diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/DifferenceISODateTimeNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/DifferenceISODateTimeNode.java new file mode 100644 index 00000000000..62c0eb26f50 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/DifferenceISODateTimeNode.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.nodes.temporal; + +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.ImportStatic; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.profiles.InlinedBranchProfile; +import com.oracle.truffle.js.nodes.JavaScriptBaseNode; +import com.oracle.truffle.js.nodes.access.EnumerableOwnPropertyNamesNode; +import com.oracle.truffle.js.runtime.BigInt; +import com.oracle.truffle.js.runtime.JSContext; +import com.oracle.truffle.js.runtime.JSRealm; +import com.oracle.truffle.js.runtime.builtins.temporal.CalendarMethodsRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.ISODateRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationObject; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDate; +import com.oracle.truffle.js.runtime.builtins.temporal.NormalizedDurationRecord; +import com.oracle.truffle.js.runtime.objects.JSObject; +import com.oracle.truffle.js.runtime.util.TemporalConstants; +import com.oracle.truffle.js.runtime.util.TemporalUtil; +import com.oracle.truffle.js.runtime.util.TemporalUtil.Unit; + +/** + * Implements the DifferenceISODateTime operation. + */ +@ImportStatic(TemporalConstants.class) +public abstract class DifferenceISODateTimeNode extends JavaScriptBaseNode { + + protected DifferenceISODateTimeNode() { + } + + public abstract NormalizedDurationRecord execute( + int y1, int mon1, int d1, int h1, int min1, int s1, int ms1, int mus1, int ns1, + int y2, int mon2, int d2, int h2, int min2, int s2, int ms2, int mus2, int ns2, + CalendarMethodsRecord calendarRec, Unit largestUnit, JSObject resolvedOptions); + + @Specialization + final NormalizedDurationRecord differencePlainDateTimeWithRounding( + int y1, int mon1, int d1, int h1, int min1, int s1, int ms1, int mus1, int ns1, + int y2, int mon2, int d2, int h2, int min2, int s2, int ms2, int mus2, int ns2, + CalendarMethodsRecord calendarRec, Unit largestUnit, JSObject options, + @Cached TemporalDifferenceDateNode differenceDate, + @Cached("createKeys(getJSContext())") EnumerableOwnPropertyNamesNode namesNode) { + JSContext ctx = getJSContext(); + JSRealm realm = getRealm(); + + BigInt timeDuration = TemporalUtil.differenceTime(h1, min1, s1, ms1, mus1, ns1, h2, min2, s2, ms2, mus2, ns2); + int timeSign = TemporalUtil.normalizedTimeDurationSign(timeDuration); + int dateSign = TemporalUtil.compareISODate(y2, mon2, d2, y1, mon1, d1); + + ISODateRecord adjustedDate = TemporalUtil.createISODateRecord(y1, mon1, d1); + if (timeSign == -dateSign) { + adjustedDate = TemporalUtil.balanceISODate(adjustedDate.year(), adjustedDate.month(), adjustedDate.day() - timeSign); + timeDuration = TemporalUtil.add24HourDaysToNormalizedTimeDuration(timeDuration, -timeSign); + } + + var date1 = JSTemporalPlainDate.create(ctx, realm, adjustedDate.year(), adjustedDate.month(), adjustedDate.day(), calendarRec.receiver(), null, + InlinedBranchProfile.getUncached()); + var date2 = JSTemporalPlainDate.create(ctx, realm, y2, mon2, d2, calendarRec.receiver(), null, InlinedBranchProfile.getUncached()); + + Unit dateLargestUnit = TemporalUtil.largerOfTwoTemporalUnits(Unit.DAY, largestUnit); + JSObject untilOptions = TemporalUtil.mergeLargestUnitOption(ctx, namesNode, options, dateLargestUnit); + + JSTemporalDurationObject dateDifference = differenceDate.execute(calendarRec, date1, date2, dateLargestUnit, untilOptions); + double days = dateDifference.getDays(); + if (largestUnit != dateLargestUnit) { + timeDuration = TemporalUtil.add24HourDaysToNormalizedTimeDuration(timeDuration, days); + days = 0; + } + return TemporalUtil.createNormalizedDurationRecord(dateDifference.getYears(), dateDifference.getMonths(), dateDifference.getWeeks(), days, timeDuration); + } +} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/DifferencePlainDateTimeWithRoundingNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/DifferencePlainDateTimeWithRoundingNode.java new file mode 100644 index 00000000000..ffb9130e24e --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/DifferencePlainDateTimeWithRoundingNode.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.nodes.temporal; + +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.ImportStatic; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.js.nodes.JavaScriptBaseNode; +import com.oracle.truffle.js.runtime.BigInt; +import com.oracle.truffle.js.runtime.builtins.temporal.CalendarMethodsRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.ISODateTimeRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateObject; +import com.oracle.truffle.js.runtime.builtins.temporal.NormalizedDurationRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.TemporalDurationWithTotalRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.TimeDurationRecord; +import com.oracle.truffle.js.runtime.objects.JSObject; +import com.oracle.truffle.js.runtime.util.TemporalConstants; +import com.oracle.truffle.js.runtime.util.TemporalUtil; +import com.oracle.truffle.js.runtime.util.TemporalUtil.RoundingMode; +import com.oracle.truffle.js.runtime.util.TemporalUtil.Unit; + +/** + * Implements the DifferencePlainDateTimeWithRounding operation. + */ +@ImportStatic(TemporalConstants.class) +public abstract class DifferencePlainDateTimeWithRoundingNode extends JavaScriptBaseNode { + + protected DifferencePlainDateTimeWithRoundingNode() { + } + + public abstract TemporalDurationWithTotalRecord execute( + JSTemporalPlainDateObject plainDate1, int h1, int min1, int s1, int ms1, int mus1, int ns1, + int y2, int mon2, int d2, int h2, int min2, int s2, int ms2, int mus2, int ns2, + CalendarMethodsRecord calendarRec, Unit largestUnit, int roundingIncrement, Unit smallestUnit, RoundingMode roundingMode, JSObject resolvedOptions); + + @Specialization + static TemporalDurationWithTotalRecord differencePlainDateTimeWithRounding( + JSTemporalPlainDateObject plainDate1, int h1, int min1, int s1, int ms1, int mus1, int ns1, + int y2, int mon2, int d2, int h2, int min2, int s2, int ms2, int mus2, int ns2, + CalendarMethodsRecord calendarRec, Unit largestUnit, int roundingIncrement, Unit smallestUnit, RoundingMode roundingMode, JSObject resolvedOptions, + @Cached DifferenceISODateTimeNode differenceISODateTime, + @Cached RoundRelativeDurationNode roundRelativeDuration) { + int y1 = plainDate1.getYear(); + int mon1 = plainDate1.getMonth(); + int d1 = plainDate1.getDay(); + if (TemporalUtil.compareISODateTime( + y1, mon1, d1, h1, min1, s1, ms1, mus1, ns1, + y2, mon2, d2, h2, min2, s2, ms2, mus2, ns2) == 0) { + return new TemporalDurationWithTotalRecord(JSTemporalDurationRecord.createZero(), 0); + } + + NormalizedDurationRecord diff = differenceISODateTime.execute( + y1, mon1, d1, h1, min1, s1, ms1, mus1, ns1, + y2, mon2, d2, h2, min2, s2, ms2, mus2, ns2, + calendarRec, largestUnit, resolvedOptions); + if (smallestUnit == Unit.NANOSECOND && roundingIncrement == 1) { + BigInt normWithDays = TemporalUtil.add24HourDaysToNormalizedTimeDuration(diff.normalizedTimeTotalNanoseconds(), diff.days()); + TimeDurationRecord timeResult = TemporalUtil.balanceTimeDuration(normWithDays, largestUnit); + double total = normWithDays.doubleValue(); + var durationRecord = JSTemporalDurationRecord.createWeeks(diff.years(), diff.months(), diff.weeks(), diff.days(), + timeResult.hours(), timeResult.minutes(), timeResult.seconds(), + timeResult.milliseconds(), timeResult.microseconds(), timeResult.nanoseconds()); + return new TemporalDurationWithTotalRecord(durationRecord, total); + } + + ISODateTimeRecord dateTime = new ISODateTimeRecord(y1, mon1, d1, h1, min1, s1, ms1, mus1, ns1); + BigInt destEpochNs = TemporalUtil.getUTCEpochNanoseconds(y2, mon2, d2, h2, min2, s2, ms2, mus2, ns2); + return roundRelativeDuration.execute(diff, destEpochNs, dateTime, calendarRec, null, largestUnit, roundingIncrement, smallestUnit, roundingMode); + } +} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/DifferenceZonedDateTimeNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/DifferenceZonedDateTimeNode.java new file mode 100644 index 00000000000..ddeda6432f0 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/DifferenceZonedDateTimeNode.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.nodes.temporal; + +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.ImportStatic; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.profiles.InlinedBranchProfile; +import com.oracle.truffle.js.nodes.JavaScriptBaseNode; +import com.oracle.truffle.js.nodes.access.EnumerableOwnPropertyNamesNode; +import com.oracle.truffle.js.runtime.BigInt; +import com.oracle.truffle.js.runtime.Errors; +import com.oracle.truffle.js.runtime.JSContext; +import com.oracle.truffle.js.runtime.JSRealm; +import com.oracle.truffle.js.runtime.builtins.temporal.CalendarMethodsRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.ISODateRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationObject; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalInstant; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalInstantObject; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDate; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateTime; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateTimeObject; +import com.oracle.truffle.js.runtime.builtins.temporal.NormalizedDurationRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.TimeZoneMethodsRecord; +import com.oracle.truffle.js.runtime.objects.JSDynamicObject; +import com.oracle.truffle.js.runtime.objects.JSObject; +import com.oracle.truffle.js.runtime.util.TemporalConstants; +import com.oracle.truffle.js.runtime.util.TemporalUtil; +import com.oracle.truffle.js.runtime.util.TemporalUtil.Disambiguation; +import com.oracle.truffle.js.runtime.util.TemporalUtil.Unit; + +/** + * Implements the DifferenceZonedDateTime operation. + */ +@ImportStatic(TemporalConstants.class) +public abstract class DifferenceZonedDateTimeNode extends JavaScriptBaseNode { + + protected DifferenceZonedDateTimeNode() { + } + + public abstract NormalizedDurationRecord execute(BigInt ns1, BigInt ns2, + TimeZoneMethodsRecord timeZoneRec, CalendarMethodsRecord calendarRec, + Unit largestUnit, JSDynamicObject options, JSTemporalPlainDateTimeObject startDateTime); + + @Specialization + final NormalizedDurationRecord differenceZonedDateTime(BigInt ns1, BigInt ns2, + TimeZoneMethodsRecord timeZoneRec, CalendarMethodsRecord calendarRec, + Unit largestUnit, JSDynamicObject options, JSTemporalPlainDateTimeObject startDateTime, + @Cached TemporalDifferenceDateNode differenceDateNode, + @Cached("createKeys(getJSContext())") EnumerableOwnPropertyNamesNode namesNode) { + int sign = ns2.compareTo(ns1); + if (sign == 0) { // ns1 == ns2 + return new NormalizedDurationRecord(0, 0, 0, 0, TemporalUtil.zeroTimeDuration()); + } + + JSContext ctx = getJSContext(); + JSRealm realm = getRealm(); + + JSTemporalInstantObject endInstant = JSTemporalInstant.create(ctx, realm, ns2); + JSTemporalPlainDateTimeObject endDateTime = TemporalUtil.builtinTimeZoneGetPlainDateTimeFor(ctx, realm, timeZoneRec, endInstant, calendarRec.receiver()); + int maxDayCorrection = sign == 1 ? 2 : 1; + int dayCorrection = 0; + + BigInt timeDuration = TemporalUtil.differenceTime( + startDateTime.getHour(), startDateTime.getMinute(), startDateTime.getSecond(), + startDateTime.getMillisecond(), startDateTime.getMicrosecond(), startDateTime.getNanosecond(), + endDateTime.getHour(), endDateTime.getMinute(), endDateTime.getSecond(), + endDateTime.getMillisecond(), endDateTime.getMicrosecond(), endDateTime.getNanosecond()); + int normalizedTimeDurationSign = TemporalUtil.normalizedTimeDurationSign(timeDuration); + if (normalizedTimeDurationSign == -sign) { + dayCorrection++; + } + + JSTemporalPlainDateTimeObject intermediateDateTime = null; + BigInt norm = null; + boolean success = false; + for (; dayCorrection <= maxDayCorrection; dayCorrection++) { + ISODateRecord intermediateDate = TemporalUtil.balanceISODate(endDateTime.getYear(), endDateTime.getMonth(), endDateTime.getDay() - dayCorrection * sign); + intermediateDateTime = JSTemporalPlainDateTime.create(ctx, realm, + intermediateDate.year(), intermediateDate.month(), intermediateDate.day(), + startDateTime.getHour(), startDateTime.getMinute(), startDateTime.getSecond(), + startDateTime.getMillisecond(), startDateTime.getMicrosecond(), startDateTime.getNanosecond(), calendarRec.receiver()); + var intermediateInstant = TemporalUtil.builtinTimeZoneGetInstantFor(ctx, realm, timeZoneRec, intermediateDateTime, Disambiguation.COMPATIBLE); + BigInt intermediateNs = intermediateInstant.getNanoseconds(); + norm = TemporalUtil.normalizedTimeDurationFromEpochNanosecondsDifference(ns2, intermediateNs); + int timeSign = TemporalUtil.normalizedTimeDurationSign(norm); + if (sign != -timeSign) { + success = true; + break; + } + } + if (success) { + var date1 = JSTemporalPlainDate.create(ctx, realm, startDateTime.getYear(), startDateTime.getMonth(), startDateTime.getDay(), calendarRec.receiver(), + null, InlinedBranchProfile.getUncached()); + var date2 = JSTemporalPlainDate.create(ctx, realm, intermediateDateTime.getYear(), intermediateDateTime.getMonth(), intermediateDateTime.getDay(), calendarRec.receiver(), + null, InlinedBranchProfile.getUncached()); + Unit dateLargestUnit = TemporalUtil.largerOfTwoTemporalUnits(largestUnit, Unit.DAY); + JSObject untilOptions = TemporalUtil.mergeLargestUnitOption(ctx, namesNode, options, dateLargestUnit); + JSTemporalDurationObject dateDifference = differenceDateNode.execute(calendarRec, date1, date2, dateLargestUnit, untilOptions); + return TemporalUtil.createNormalizedDurationRecord(dateDifference.getYears(), dateDifference.getMonths(), dateDifference.getWeeks(), dateDifference.getDays(), norm); + } + throw Errors.createRangeError("custom calendar or time zone methods returned inconsistent values"); + } +} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/DifferenceZonedDateTimeWithRoundingNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/DifferenceZonedDateTimeWithRoundingNode.java new file mode 100644 index 00000000000..f55a0e814da --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/DifferenceZonedDateTimeWithRoundingNode.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.nodes.temporal; + +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.ImportStatic; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.js.nodes.JavaScriptBaseNode; +import com.oracle.truffle.js.runtime.BigInt; +import com.oracle.truffle.js.runtime.builtins.temporal.CalendarMethodsRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.ISODateTimeRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateTimeObject; +import com.oracle.truffle.js.runtime.builtins.temporal.TemporalDurationWithTotalRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.TimeDurationRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.TimeZoneMethodsRecord; +import com.oracle.truffle.js.runtime.objects.JSObject; +import com.oracle.truffle.js.runtime.util.TemporalConstants; +import com.oracle.truffle.js.runtime.util.TemporalUtil; +import com.oracle.truffle.js.runtime.util.TemporalUtil.RoundingMode; +import com.oracle.truffle.js.runtime.util.TemporalUtil.Unit; + +/** + * Implements the DifferenceZonedDateTimeWithRounding operation. + */ +@ImportStatic(TemporalConstants.class) +public abstract class DifferenceZonedDateTimeWithRoundingNode extends JavaScriptBaseNode { + + protected DifferenceZonedDateTimeWithRoundingNode() { + } + + public abstract TemporalDurationWithTotalRecord execute(BigInt ns1, BigInt ns2, + CalendarMethodsRecord calendarRec, TimeZoneMethodsRecord timeZoneRec, + JSTemporalPlainDateTimeObject precalculatedPlainDateTime, JSObject resolvedOptions, + Unit largestUnit, int roundingIncrement, Unit smallestUnit, RoundingMode roundingMode); + + @Specialization + static TemporalDurationWithTotalRecord differenceZonedDateTimeWithRounding(BigInt ns1, BigInt ns2, + CalendarMethodsRecord calendarRec, TimeZoneMethodsRecord timeZoneRec, + JSTemporalPlainDateTimeObject precalculatedPlainDateTime, JSObject resolvedOptions, + Unit largestUnit, int roundingIncrement, Unit smallestUnit, RoundingMode roundingMode, + @Cached DifferenceZonedDateTimeNode differenceZonedDateTime, + @Cached RoundRelativeDurationNode roundRelativeDuration) { + if (!largestUnit.isCalendarUnit() && largestUnit != Unit.DAY) { + var diffRecord = TemporalUtil.differenceInstant(ns1, ns2, roundingIncrement, smallestUnit, roundingMode); + BigInt norm = diffRecord.normalizedTimeDuration(); + TimeDurationRecord result = TemporalUtil.balanceTimeDuration(norm, largestUnit); + var durationRecord = JSTemporalDurationRecord.createWeeks(0, 0, 0, 0, + result.hours(), result.minutes(), result.seconds(), result.milliseconds(), result.microseconds(), result.nanoseconds()); + return new TemporalDurationWithTotalRecord(durationRecord, diffRecord.total()); + } + + var difference = differenceZonedDateTime.execute(ns1, ns2, timeZoneRec, calendarRec, largestUnit, resolvedOptions, precalculatedPlainDateTime); + boolean roundingGranularityIsNoop = smallestUnit == Unit.NANOSECOND && roundingIncrement == 1; + if (roundingGranularityIsNoop) { + TimeDurationRecord timeResult = TemporalUtil.balanceTimeDuration(difference.normalizedTimeTotalNanoseconds(), Unit.HOUR); + double total = difference.normalizedTimeTotalNanoseconds().doubleValue(); + var durationRecord = JSTemporalDurationRecord.createWeeks(difference.years(), difference.months(), difference.weeks(), difference.days(), + timeResult.hours(), timeResult.minutes(), timeResult.seconds(), timeResult.milliseconds(), timeResult.microseconds(), timeResult.nanoseconds()); + return new TemporalDurationWithTotalRecord(durationRecord, total); + } + + ISODateTimeRecord dateTime = new ISODateTimeRecord( + precalculatedPlainDateTime.getYear(), precalculatedPlainDateTime.getMonth(), precalculatedPlainDateTime.getDay(), + precalculatedPlainDateTime.getHour(), precalculatedPlainDateTime.getMinute(), precalculatedPlainDateTime.getSecond(), + precalculatedPlainDateTime.getMillisecond(), precalculatedPlainDateTime.getMicrosecond(), precalculatedPlainDateTime.getNanosecond()); + return roundRelativeDuration.execute(difference, ns2, dateTime, calendarRec, timeZoneRec, largestUnit, roundingIncrement, smallestUnit, roundingMode); + } +} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/RoundRelativeDurationNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/RoundRelativeDurationNode.java new file mode 100644 index 00000000000..8856e9963c8 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/RoundRelativeDurationNode.java @@ -0,0 +1,401 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.nodes.temporal; + +import java.math.BigDecimal; +import java.math.MathContext; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.profiles.InlinedBranchProfile; +import com.oracle.truffle.js.nodes.JavaScriptBaseNode; +import com.oracle.truffle.js.runtime.BigInt; +import com.oracle.truffle.js.runtime.Errors; +import com.oracle.truffle.js.runtime.JSContext; +import com.oracle.truffle.js.runtime.JSRealm; +import com.oracle.truffle.js.runtime.builtins.JSOrdinary; +import com.oracle.truffle.js.runtime.builtins.temporal.CalendarMethodsRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.ISODateRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.ISODateTimeRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDateTimeRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationObject; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDate; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateObject; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateTime; +import com.oracle.truffle.js.runtime.builtins.temporal.NormalizedDurationRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.TemporalDurationWithTotalRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.TimeZoneMethodsRecord; +import com.oracle.truffle.js.runtime.objects.JSObject; +import com.oracle.truffle.js.runtime.objects.JSObjectUtil; +import com.oracle.truffle.js.runtime.objects.Undefined; +import com.oracle.truffle.js.runtime.util.TemporalConstants; +import com.oracle.truffle.js.runtime.util.TemporalUtil; +import com.oracle.truffle.js.runtime.util.TemporalUtil.Disambiguation; +import com.oracle.truffle.js.runtime.util.TemporalUtil.RoundingMode; +import com.oracle.truffle.js.runtime.util.TemporalUtil.Unit; +import com.oracle.truffle.js.runtime.util.TemporalUtil.UnsignedRoundingMode; + +/** + * Implements Temporal RoundRelativeDuration and related operations. + */ +public abstract class RoundRelativeDurationNode extends JavaScriptBaseNode { + + protected RoundRelativeDurationNode() { + } + + public abstract TemporalDurationWithTotalRecord execute(NormalizedDurationRecord duration, BigInt destEpochNs, ISODateTimeRecord dateTime, + CalendarMethodsRecord calendarRec, TimeZoneMethodsRecord timeZoneRec, + Unit largestUnit, int increment, Unit smallestUnit, RoundingMode roundingMode); + + @Specialization + protected final TemporalDurationWithTotalRecord roundRelativeDuration(NormalizedDurationRecord duration0, BigInt destEpochNs, ISODateTimeRecord dateTime, + CalendarMethodsRecord calendarRec, TimeZoneMethodsRecord timeZoneRec, + Unit largestUnit0, int increment, Unit smallestUnit, RoundingMode roundingMode, + @Cached TemporalAddDateTimeNode addDateTimeNode, + @Cached TemporalDifferenceDateNode differenceDateNode, + @Cached InlinedBranchProfile errorBranch) { + NormalizedDurationRecord duration = duration0; + Unit largestUnit = largestUnit0; + boolean irregularLengthUnit = smallestUnit.isCalendarUnit(); + if (timeZoneRec != null && smallestUnit == Unit.DAY) { + irregularLengthUnit = true; + } + int sign = TemporalUtil.durationSign(duration.years(), duration.months(), duration.weeks(), duration.days(), + TemporalUtil.normalizedTimeDurationSign(duration.normalizedTimeTotalNanoseconds()), 0, 0, 0, 0, 0) < 0 ? -1 : 1; + DurationNudgeResultRecord nudgeResult; + if (irregularLengthUnit) { + nudgeResult = nudgeToCalendarUnit(sign, duration, destEpochNs, dateTime, calendarRec, timeZoneRec, increment, smallestUnit, roundingMode, + addDateTimeNode, differenceDateNode, errorBranch); + } else if (timeZoneRec != null) { + nudgeResult = nudgeToZonedTime(sign, duration, dateTime, calendarRec, timeZoneRec, increment, smallestUnit, roundingMode, + addDateTimeNode, errorBranch); + } else { + nudgeResult = nudgeToDayOrTime(duration, destEpochNs, largestUnit, increment, smallestUnit, roundingMode); + } + duration = nudgeResult.duration(); + if (nudgeResult.didExpandCalendarUnit() && smallestUnit != Unit.WEEK) { + Unit startUnit = TemporalUtil.largerOfTwoTemporalUnits(smallestUnit, Unit.DAY); + duration = bubbleRelativeDuration(sign, duration, nudgeResult.nudgedEpochNs(), dateTime, calendarRec, timeZoneRec, largestUnit, startUnit, + addDateTimeNode, errorBranch); + } + if (largestUnit.isCalendarUnit() || largestUnit == Unit.DAY) { + largestUnit = Unit.HOUR; + } + var balanceResult = TemporalUtil.balanceTimeDuration(duration.normalizedTimeTotalNanoseconds(), largestUnit); + return new TemporalDurationWithTotalRecord(JSTemporalDurationRecord.createWeeks( + duration.years(), duration.months(), duration.weeks(), duration.days(), + balanceResult.hours(), balanceResult.minutes(), balanceResult.seconds(), + balanceResult.milliseconds(), balanceResult.microseconds(), balanceResult.nanoseconds()), nudgeResult.total()); + } + + private DurationNudgeResultRecord nudgeToCalendarUnit(int sign, NormalizedDurationRecord duration, BigInt destEpochNs, ISODateTimeRecord dateTime, CalendarMethodsRecord calendarRec, + TimeZoneMethodsRecord timeZoneRec, int increment, Unit unit, RoundingMode roundingMode, + TemporalAddDateTimeNode addDateTimeNode, TemporalDifferenceDateNode differenceDateNode, InlinedBranchProfile errorBranch) { + JSRealm realm = getRealm(); + JSContext ctx = getJSContext(); + double r1; + double r2; + NormalizedDurationRecord startDuration; + NormalizedDurationRecord endDuration; + switch (unit) { + case YEAR -> { + double years = TemporalUtil.roundNumberToIncrement(duration.years(), increment, RoundingMode.TRUNC); + r1 = years; + r2 = years + increment * sign; + startDuration = TemporalUtil.createNormalizedDurationRecord(r1, 0, 0, 0, TemporalUtil.zeroTimeDuration()); + endDuration = TemporalUtil.createNormalizedDurationRecord(r2, 0, 0, 0, TemporalUtil.zeroTimeDuration()); + } + case MONTH -> { + double months = TemporalUtil.roundNumberToIncrement(duration.months(), increment, RoundingMode.TRUNC); + r1 = months; + r2 = months + increment * sign; + startDuration = TemporalUtil.createNormalizedDurationRecord(duration.years(), r1, 0, 0, TemporalUtil.zeroTimeDuration()); + endDuration = TemporalUtil.createNormalizedDurationRecord(duration.years(), r2, 0, 0, TemporalUtil.zeroTimeDuration()); + } + case WEEK -> { + ISODateRecord isoResult1 = TemporalUtil.balanceISODate(dateTime.year() + duration.years(), dateTime.month() + duration.months(), dateTime.day()); + ISODateRecord isoResult2 = TemporalUtil.balanceISODate(dateTime.year() + duration.years(), dateTime.month() + duration.months(), dateTime.day() + duration.days()); + JSTemporalPlainDateObject weeksStart = JSTemporalPlainDate.create(ctx, realm, + isoResult1.year(), isoResult1.month(), isoResult1.day(), calendarRec.receiver(), this, errorBranch); + JSTemporalPlainDateObject weeksEnd = JSTemporalPlainDate.create(ctx, realm, + isoResult2.year(), isoResult2.month(), isoResult2.day(), calendarRec.receiver(), this, errorBranch); + JSObject untilOptions = JSOrdinary.createWithNullPrototype(ctx); + JSObjectUtil.putDataProperty(untilOptions, TemporalConstants.LARGEST_UNIT, TemporalConstants.WEEK); + JSTemporalDurationObject untilResult = differenceDateNode.execute(calendarRec, weeksStart, weeksEnd, Unit.WEEK, untilOptions); + double weeks = TemporalUtil.roundNumberToIncrement(duration.weeks() + untilResult.getWeeks(), increment, RoundingMode.TRUNC); + r1 = weeks; + r2 = weeks + increment * sign; + startDuration = TemporalUtil.createNormalizedDurationRecord(duration.years(), duration.months(), r1, 0, TemporalUtil.zeroTimeDuration()); + endDuration = TemporalUtil.createNormalizedDurationRecord(duration.years(), duration.months(), r2, 0, TemporalUtil.zeroTimeDuration()); + } + case DAY -> { + double days = TemporalUtil.roundNumberToIncrement(duration.days(), increment, RoundingMode.TRUNC); + r1 = days; + r2 = days + increment * sign; + startDuration = TemporalUtil.createNormalizedDurationRecord(duration.years(), duration.months(), duration.weeks(), r1, TemporalUtil.zeroTimeDuration()); + endDuration = TemporalUtil.createNormalizedDurationRecord(duration.years(), duration.months(), duration.weeks(), r2, TemporalUtil.zeroTimeDuration()); + } + default -> throw Errors.shouldNotReachHereUnexpectedValue(unit); + } + JSTemporalDateTimeRecord start = addDateTimeNode.execute(dateTime.year(), dateTime.month(), dateTime.day(), + dateTime.hour(), dateTime.minute(), dateTime.second(), dateTime.millisecond(), dateTime.microsecond(), dateTime.nanosecond(), + calendarRec, + startDuration.years(), startDuration.months(), startDuration.weeks(), startDuration.days(), startDuration.normalizedTimeTotalNanoseconds(), + Undefined.instance); + JSTemporalDateTimeRecord end = addDateTimeNode.execute(dateTime.year(), dateTime.month(), dateTime.day(), + dateTime.hour(), dateTime.minute(), dateTime.second(), dateTime.millisecond(), dateTime.microsecond(), dateTime.nanosecond(), + calendarRec, + endDuration.years(), endDuration.months(), endDuration.weeks(), endDuration.days(), endDuration.normalizedTimeTotalNanoseconds(), + Undefined.instance); + BigInt startEpochNs; + BigInt endEpochNs; + if (timeZoneRec == null) { + startEpochNs = TemporalUtil.getUTCEpochNanoseconds(start.getYear(), start.getMonth(), start.getDay(), + start.getHour(), start.getMinute(), start.getSecond(), start.getMillisecond(), start.getMicrosecond(), start.getNanosecond()); + endEpochNs = TemporalUtil.getUTCEpochNanoseconds(end.getYear(), end.getMonth(), end.getDay(), + end.getHour(), end.getMinute(), end.getSecond(), end.getMillisecond(), end.getMicrosecond(), end.getNanosecond()); + } else { + var startDateTime = JSTemporalPlainDateTime.create(ctx, realm, start.getYear(), start.getMonth(), start.getDay(), + start.getHour(), start.getMinute(), start.getSecond(), start.getMillisecond(), start.getMicrosecond(), start.getNanosecond(), + calendarRec.receiver(), this, errorBranch); + var startInstant = TemporalUtil.builtinTimeZoneGetInstantFor(ctx, realm, timeZoneRec, startDateTime, Disambiguation.COMPATIBLE); + startEpochNs = startInstant.getNanoseconds(); + var endDateTime = JSTemporalPlainDateTime.create(ctx, realm, end.getYear(), end.getMonth(), end.getDay(), + end.getHour(), end.getMinute(), end.getSecond(), end.getMillisecond(), end.getMicrosecond(), end.getNanosecond(), + calendarRec.receiver(), this, errorBranch); + var endInstant = TemporalUtil.builtinTimeZoneGetInstantFor(ctx, realm, timeZoneRec, endDateTime, Disambiguation.COMPATIBLE); + endEpochNs = endInstant.getNanoseconds(); + } + if (startEpochNs.compareTo(endEpochNs) == 0) { + throw Errors.createRangeError("custom calendar method returned an illegal result"); + } + boolean isNegative = sign < 0; + UnsignedRoundingMode unsignedRoundingMode = TemporalUtil.getUnsignedRoundingMode(roundingMode, isNegative); + + BigInt numerator = destEpochNs.subtract(startEpochNs); + BigInt denominator = endEpochNs.subtract(startEpochNs); + double total = computeTotal(r1, increment, sign, numerator, denominator); + // Let roundedUnit be ApplyUnsignedRoundingMode(total, r1, r2, unsignedRoundingMode). + double roundedUnit = TemporalUtil.applyUnsignedRoundingMode(numerator, denominator, r1, r2, unsignedRoundingMode); + // Possible spec bug: roundedSign = (roundedUnit - total < 0 ? -1 : 1). + int roundedSign = Double.compare(roundedUnit - total, 0); + + boolean didExpandCalendarUnit; + NormalizedDurationRecord resultDuration; + BigInt nudgedEpochNs; + if (roundedSign == sign) { + didExpandCalendarUnit = true; + resultDuration = endDuration; + nudgedEpochNs = endEpochNs; + } else { + didExpandCalendarUnit = false; + resultDuration = startDuration; + nudgedEpochNs = startEpochNs; + } + return new DurationNudgeResultRecord(resultDuration, total, nudgedEpochNs, didExpandCalendarUnit); + } + + @TruffleBoundary + private static double computeTotal(double r1, int increment, int sign, BigInt numerator, BigInt denominator) { + /* + * The following two steps cannot be implemented directly using floating-point arithmetic. + * This division can be implemented as if constructing Normalized Time Duration Records for + * the denominator and numerator of total and performing one division operation with a + * floating-point result. + */ + BigDecimal progress = new BigDecimal(numerator.bigIntegerValue()).divide(new BigDecimal(denominator.bigIntegerValue()), MathContext.DECIMAL128); + BigDecimal total = new BigDecimal(r1).add(progress.multiply(new BigDecimal(increment * sign))); + return total.doubleValue(); + } + + private DurationNudgeResultRecord nudgeToZonedTime(int sign, NormalizedDurationRecord duration, ISODateTimeRecord dateTime, CalendarMethodsRecord calendarRec, + TimeZoneMethodsRecord timeZoneRec, int increment, Unit unit, RoundingMode roundingMode, + TemporalAddDateTimeNode addDateTimeNode, InlinedBranchProfile errorBranch) { + JSRealm realm = getRealm(); + JSContext ctx = getJSContext(); + JSTemporalDateTimeRecord start = addDateTimeNode.execute(dateTime.year(), dateTime.month(), dateTime.day(), + dateTime.hour(), dateTime.minute(), dateTime.second(), dateTime.millisecond(), dateTime.microsecond(), dateTime.nanosecond(), + calendarRec, + duration.years(), duration.months(), duration.weeks(), duration.days(), TemporalUtil.zeroTimeDuration(), + Undefined.instance); + var startDateTime = JSTemporalPlainDateTime.create(ctx, realm, start.getYear(), start.getMonth(), start.getDay(), + start.getHour(), start.getMinute(), start.getSecond(), start.getMillisecond(), start.getMicrosecond(), start.getNanosecond(), + calendarRec.receiver(), this, errorBranch); + ISODateRecord endDate = TemporalUtil.balanceISODate(start.getYear(), start.getMonth(), start.getDay() + sign); + var endDateTime = JSTemporalPlainDateTime.create(ctx, realm, endDate.year(), endDate.month(), endDate.day(), + start.getHour(), start.getMinute(), start.getSecond(), start.getMillisecond(), start.getMicrosecond(), start.getNanosecond(), + calendarRec.receiver(), this, errorBranch); + var startInstant = TemporalUtil.builtinTimeZoneGetInstantFor(ctx, realm, timeZoneRec, startDateTime, Disambiguation.COMPATIBLE); + BigInt startEpochNs = startInstant.getNanoseconds(); + var endInstant = TemporalUtil.builtinTimeZoneGetInstantFor(ctx, realm, timeZoneRec, endDateTime, Disambiguation.COMPATIBLE); + BigInt endEpochNs = endInstant.getNanoseconds(); + + BigInt daySpan = TemporalUtil.normalizedTimeDurationFromEpochNanosecondsDifference(endEpochNs, startEpochNs); + assert TemporalUtil.normalizedTimeDurationSign(daySpan) == sign; + long unitLength = unit.getLengthInNanoseconds(); + BigInt roundedNorm = TemporalUtil.roundNormalizedTimeDurationToIncrement(duration.normalizedTimeTotalNanoseconds(), unitLength, increment, roundingMode); + BigInt beyondDaySpan = TemporalUtil.subtractNormalizedTimeDuration(roundedNorm, daySpan); + boolean didRoundBeyondDay; + int dayDelta; + BigInt nudgedEpochNs; + if (TemporalUtil.normalizedTimeDurationSign(beyondDaySpan) != -sign) { + didRoundBeyondDay = true; + dayDelta = sign; + roundedNorm = TemporalUtil.roundNormalizedTimeDurationToIncrement(beyondDaySpan, unitLength, increment, roundingMode); + nudgedEpochNs = TemporalUtil.addNormalizedTimeDurationToEpochNanoseconds(roundedNorm, endEpochNs); + } else { + didRoundBeyondDay = false; + dayDelta = 0; + nudgedEpochNs = TemporalUtil.addNormalizedTimeDurationToEpochNanoseconds(roundedNorm, startEpochNs); + } + var resultDuration = TemporalUtil.createNormalizedDurationRecord(duration.years(), duration.months(), duration.weeks(), duration.days() + dayDelta, roundedNorm); + return new DurationNudgeResultRecord(resultDuration, Double.NaN /* unset */, nudgedEpochNs, didRoundBeyondDay); + } + + private static DurationNudgeResultRecord nudgeToDayOrTime(NormalizedDurationRecord duration, BigInt destEpochNs, Unit largestUnit, int increment, Unit unit, RoundingMode roundingMode) { + BigInt norm = TemporalUtil.add24HourDaysToNormalizedTimeDuration(duration.normalizedTimeTotalNanoseconds(), duration.days()); + long unitLength = unit.getLengthInNanoseconds(); + double total = TemporalUtil.divideNormalizedTimeDurationAsDouble(norm, unitLength); + BigInt roundedNorm = TemporalUtil.roundNormalizedTimeDurationToIncrement(norm, unitLength, increment, roundingMode); + BigInt diffNorm = TemporalUtil.subtractNormalizedTimeDuration(roundedNorm, norm); + double wholeDays = TemporalUtil.divideNormalizedTimeDurationAsDoubleTruncate(norm, TemporalUtil.NS_PER_DAY_LONG); + double roundedWholeDays = TemporalUtil.divideNormalizedTimeDurationAsDoubleTruncate(roundedNorm, TemporalUtil.NS_PER_DAY_LONG); + double dayDelta = roundedWholeDays - wholeDays; + int dayDeltaSign = Double.compare(dayDelta, 0); + boolean didExpandDays = dayDeltaSign == TemporalUtil.normalizedTimeDurationSign(norm); + BigInt nudgedEpochNs = TemporalUtil.addNormalizedTimeDurationToEpochNanoseconds(diffNorm, destEpochNs); + double days = 0; + BigInt remainder = roundedNorm; + if (TemporalUtil.largerOfTwoTemporalUnits(largestUnit, Unit.DAY) == largestUnit) { + days = roundedWholeDays; + remainder = TemporalUtil.remainderNormalizedTimeDuration(roundedNorm, TemporalUtil.NS_PER_DAY_LONG); + } + var resultDuration = TemporalUtil.createNormalizedDurationRecord(duration.years(), duration.months(), duration.weeks(), days, remainder); + return new DurationNudgeResultRecord(resultDuration, total, nudgedEpochNs, didExpandDays); + } + + private NormalizedDurationRecord bubbleRelativeDuration(int sign, NormalizedDurationRecord duration0, BigInt nudgedEpochNs, ISODateTimeRecord dateTime, CalendarMethodsRecord calendarRec, + TimeZoneMethodsRecord timeZoneRec, Unit largestUnit, Unit smallestUnit, + TemporalAddDateTimeNode addDateTimeNode, InlinedBranchProfile errorBranch) { + assert largestUnit.isDateUnit() : largestUnit; + assert smallestUnit.isDateUnit() : smallestUnit; + NormalizedDurationRecord duration = duration0; + if (smallestUnit == Unit.YEAR) { + return duration; + } + JSRealm realm = getRealm(); + JSContext ctx = getJSContext(); + int largestUnitIndex = largestUnit.ordinal(); + int smallestUnitIndex = smallestUnit.ordinal(); + for (int unitIndex = smallestUnitIndex - 1; unitIndex >= largestUnitIndex; unitIndex--) { + Unit unit = Unit.VALUES[unitIndex]; + if (!(unit != Unit.WEEK || largestUnit == Unit.WEEK)) { + continue; + } + NormalizedDurationRecord endDuration; + switch (unit) { + case YEAR -> { + double years = duration.years() + sign; + endDuration = TemporalUtil.createNormalizedDurationRecord(years, 0, 0, 0, TemporalUtil.zeroTimeDuration()); + } + case MONTH -> { + double months = duration.months() + sign; + endDuration = TemporalUtil.createNormalizedDurationRecord(duration.years(), months, 0, 0, TemporalUtil.zeroTimeDuration()); + } + case WEEK -> { + double weeks = duration.weeks() + sign; + endDuration = TemporalUtil.createNormalizedDurationRecord(duration.years(), duration.months(), weeks, 0, TemporalUtil.zeroTimeDuration()); + } + case DAY -> { + double days = duration.days() + sign; + endDuration = TemporalUtil.createNormalizedDurationRecord(duration.years(), duration.months(), duration.weeks(), days, TemporalUtil.zeroTimeDuration()); + } + default -> throw Errors.shouldNotReachHereUnexpectedValue(unit); + } + JSTemporalDateTimeRecord end = addDateTimeNode.execute(dateTime.year(), dateTime.month(), dateTime.day(), + dateTime.hour(), dateTime.minute(), dateTime.second(), dateTime.millisecond(), dateTime.microsecond(), dateTime.nanosecond(), + calendarRec, + endDuration.years(), endDuration.months(), endDuration.weeks(), endDuration.days(), endDuration.normalizedTimeTotalNanoseconds(), + Undefined.instance); + BigInt endEpochNs; + if (timeZoneRec == null) { + endEpochNs = TemporalUtil.getUTCEpochNanoseconds(end.getYear(), end.getMonth(), end.getDay(), + end.getHour(), end.getMinute(), end.getSecond(), end.getMillisecond(), end.getMicrosecond(), end.getNanosecond()); + } else { + var endDateTime = JSTemporalPlainDateTime.create(ctx, realm, end.getYear(), end.getMonth(), end.getDay(), + end.getHour(), end.getMinute(), end.getSecond(), end.getMillisecond(), end.getMicrosecond(), end.getNanosecond(), + calendarRec.receiver(), this, errorBranch); + var endInstant = TemporalUtil.builtinTimeZoneGetInstantFor(ctx, realm, timeZoneRec, endDateTime, Disambiguation.COMPATIBLE); + endEpochNs = endInstant.getNanoseconds(); + } + BigInt beyondEnd = nudgedEpochNs.subtract(endEpochNs); + int beyondEndSign = beyondEnd.signum(); + if (beyondEndSign != -sign) { + duration = endDuration; + } else { + break; + } + } + return duration; + } + + /** + * A Duration Nudge Result Record is a value used to represent the result of rounding a duration + * up or down to an increment relative to a date-time. Returned by the following operations: + * NudgeToCalendarUnit, NudgeToZonedTime, NudgeToDayOrTime. + * + * @param duration The resulting duration. + * @param total The possibly fractional total of the smallest unit before the rounding + * operation, for use in Temporal.Duration.prototype.total, or NaN if not relevant. + * @param nudgedEpochNs The epoch time corresponding to the rounded duration, relative to the + * starting point. + * @param didExpandCalendarUnit Whether the rounding operation caused the duration to expand to + * the next day or larger unit. + */ + public record DurationNudgeResultRecord( + NormalizedDurationRecord duration, + double total, + BigInt nudgedEpochNs, + boolean didExpandCalendarUnit) { + } +} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalAddDateNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalAddDateNode.java index b1d57485a8a..213fdda5406 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalAddDateNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalAddDateNode.java @@ -45,6 +45,7 @@ import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.js.nodes.JavaScriptBaseNode; import com.oracle.truffle.js.nodes.function.JSFunctionCallNode; +import com.oracle.truffle.js.runtime.BigInt; import com.oracle.truffle.js.runtime.JSArguments; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRealm; @@ -52,6 +53,7 @@ import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationObject; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDate; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateObject; +import com.oracle.truffle.js.runtime.builtins.temporal.TimeDurationRecord; import com.oracle.truffle.js.runtime.objects.JSDynamicObject; import com.oracle.truffle.js.runtime.util.TemporalUtil; import com.oracle.truffle.js.runtime.util.TemporalUtil.Overflow; @@ -79,12 +81,13 @@ protected JSTemporalPlainDateObject addDate(CalendarMethodsRecord calendarRec, J Object addedDate = callDateAddNode.executeCall(JSArguments.create(calendar, calendarRec.dateAdd(), plainDate, duration, options)); return TemporalUtil.requireTemporalDate(addedDate, this, errorBranch); } else { - JSContext ctx = getLanguage().getJSContext(); + JSContext ctx = getJSContext(); JSRealm realm = getRealm(); Overflow overflow = TemporalUtil.toTemporalOverflow(options, getOptionNode); - double days = TemporalUtil.balanceTimeDuration(duration.getDays(), - duration.getHours(), duration.getMinutes(), duration.getSeconds(), - duration.getMilliseconds(), duration.getMicroseconds(), duration.getNanoseconds(), Unit.DAY).days(); + BigInt norm = TemporalUtil.normalizeTimeDuration(duration.getHours(), duration.getMinutes(), duration.getSeconds(), + duration.getMilliseconds(), duration.getMicroseconds(), duration.getNanoseconds()); + TimeDurationRecord balancedDuration = TemporalUtil.balanceTimeDuration(norm, Unit.DAY); + double days = duration.getDays() + balancedDuration.days(); var result = TemporalUtil.addISODate(plainDate.getYear(), plainDate.getMonth(), plainDate.getDay(), 0, 0, 0, days, overflow); return JSTemporalPlainDate.create(ctx, realm, result.year(), result.month(), result.day(), calendarRec.receiver(), this, errorBranch); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalAddDateTimeNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalAddDateTimeNode.java new file mode 100644 index 00000000000..c533aafbbf1 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalAddDateTimeNode.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.nodes.temporal; + +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.profiles.InlinedBranchProfile; +import com.oracle.truffle.js.nodes.JavaScriptBaseNode; +import com.oracle.truffle.js.runtime.BigInt; +import com.oracle.truffle.js.runtime.JSContext; +import com.oracle.truffle.js.runtime.JSRealm; +import com.oracle.truffle.js.runtime.builtins.temporal.CalendarMethodsRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDateTimeRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDuration; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationObject; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDate; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateObject; +import com.oracle.truffle.js.runtime.builtins.temporal.TimeRecord; +import com.oracle.truffle.js.runtime.objects.JSDynamicObject; +import com.oracle.truffle.js.runtime.util.TemporalUtil; + +/** + * Implementation of the Temporal AddDateTime operation. + */ +public abstract class TemporalAddDateTimeNode extends JavaScriptBaseNode { + + protected TemporalAddDateTimeNode() { + } + + public abstract JSTemporalDateTimeRecord execute(int year, int month, int day, + int hour, int minute, int second, int millisecond, int microsecond, double nanosecond, + CalendarMethodsRecord calendarRec, + double years, double months, double weeks, double days, BigInt normalizedTimeDuration, + JSDynamicObject options); + + @Specialization + protected JSTemporalDateTimeRecord addDateTime(int year, int month, int day, + int hour, int minute, int second, int millisecond, int microsecond, double nanosecond, + CalendarMethodsRecord calendarRec, + double years, double months, double weeks, double days, BigInt normalizedTimeDuration, + JSDynamicObject options, + @Cached TemporalAddDateNode addDateNode, + @Cached InlinedBranchProfile errorBranch) { + JSContext ctx = getJSContext(); + JSRealm realm = getRealm(); + + TimeRecord timeResult = TemporalUtil.addTime(hour, minute, second, millisecond, microsecond, nanosecond, normalizedTimeDuration, this, errorBranch); + JSTemporalPlainDateObject datePart = JSTemporalPlainDate.create(ctx, realm, year, month, day, calendarRec.receiver(), this, errorBranch); + JSTemporalDurationObject dateDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, years, months, weeks, days + timeResult.days(), 0L, 0L, 0L, 0L, 0L, 0L, this, errorBranch); + JSTemporalPlainDateObject addedDate = addDateNode.execute(calendarRec, datePart, dateDuration, options); + return JSTemporalDateTimeRecord.create(addedDate.getYear(), addedDate.getMonth(), addedDate.getDay(), + timeResult.hour(), timeResult.minute(), timeResult.second(), timeResult.millisecond(), timeResult.microsecond(), timeResult.nanosecond()); + } + +} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalDurationAddNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalDurationAddNode.java deleted file mode 100644 index 343d29f1a89..00000000000 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalDurationAddNode.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * The Universal Permissive License (UPL), Version 1.0 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or - * data (collectively the "Software"), free of charge and under any and all - * copyright rights in the Software, and any and all patent rights owned or - * freely licensable by each licensor hereunder covering either (i) the - * unmodified Software as contributed to or provided by such licensor, or (ii) - * the Larger Works (as defined below), to deal in both - * - * (a) the Software, and - * - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * - * The above copyright notice and either this complete permission notice or at a - * minimum a reference to the UPL must be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.oracle.truffle.js.nodes.temporal; - -import static com.oracle.truffle.js.runtime.util.TemporalConstants.LARGEST_UNIT; -import static com.oracle.truffle.js.runtime.util.TemporalUtil.dtol; - -import java.util.stream.DoubleStream; - -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.profiles.InlinedBranchProfile; -import com.oracle.truffle.api.profiles.InlinedConditionProfile; -import com.oracle.truffle.js.lang.JavaScriptLanguage; -import com.oracle.truffle.js.nodes.JavaScriptBaseNode; -import com.oracle.truffle.js.nodes.access.EnumerableOwnPropertyNamesNode; -import com.oracle.truffle.js.runtime.BigInt; -import com.oracle.truffle.js.runtime.Errors; -import com.oracle.truffle.js.runtime.JSContext; -import com.oracle.truffle.js.runtime.JSRealm; -import com.oracle.truffle.js.runtime.JSRuntime; -import com.oracle.truffle.js.runtime.builtins.JSOrdinary; -import com.oracle.truffle.js.runtime.builtins.temporal.CalendarMethodsRecord; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalCalendarHolder; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDuration; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationObject; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationRecord; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateObject; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateTimeObject; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalZonedDateTimeObject; -import com.oracle.truffle.js.runtime.builtins.temporal.TimeDurationRecord; -import com.oracle.truffle.js.runtime.builtins.temporal.TimeZoneMethodsRecord; -import com.oracle.truffle.js.runtime.objects.JSObject; -import com.oracle.truffle.js.runtime.objects.JSObjectUtil; -import com.oracle.truffle.js.runtime.objects.Undefined; -import com.oracle.truffle.js.runtime.util.TemporalUtil; - -/** - * Implementation of the Temporal addDuration operation. - */ -public abstract class TemporalDurationAddNode extends JavaScriptBaseNode { - - @Child EnumerableOwnPropertyNamesNode namesNode; - - protected TemporalDurationAddNode() { - JSContext ctx = JavaScriptLanguage.get(null).getJSContext(); - this.namesNode = EnumerableOwnPropertyNamesNode.createKeys(ctx); - } - - public abstract JSTemporalDurationRecord execute(double y1, double mon1, double w1, double d1, double h1, double min1, double s1, double ms1, double mus1, double ns1, - double y2, double mon2, double w2, double d2, double h2, double min2, double s2, double ms2, double mus2, double ns2, - JSTemporalCalendarHolder relativeTo, CalendarMethodsRecord calendarRec, TimeZoneMethodsRecord timeZoneRec, - JSTemporalPlainDateTimeObject precalculatedPlainDateTime); - - // @Cached parameters create unused variable in generated code, see GR-37931 - @Specialization - protected JSTemporalDurationRecord add(double y1, double mon1, double w1, double d1, double h1, double min1, double s1, double ms1, double mus1, double ns1, - double y2, double mon2, double w2, double d2, double h2, double min2, double s2, double ms2, double mus2, double ns2, - JSTemporalCalendarHolder relativeTo, CalendarMethodsRecord calendarRec, TimeZoneMethodsRecord timeZoneRec, - JSTemporalPlainDateTimeObject precalculatedPlainDateTime, - @Cached TemporalRoundDurationNode roundDurationNode, - @Cached TemporalAddDateNode addDateNode, - @Cached TemporalDifferenceDateNode differenceDateNode, - @Cached InlinedBranchProfile errorBranch, - @Cached InlinedBranchProfile relativeToUndefinedBranch, - @Cached InlinedBranchProfile relativeToPlainDateBranch, - @Cached InlinedBranchProfile relativeToZonedDateTimeBranch, - @Cached InlinedConditionProfile largetUnitYMWDProfile) { - assert DoubleStream.of( - y1, mon1, w1, d1, h1, min1, s1, ms1, mus1, ns1, - y2, mon2, w2, d2, h2, min2, s2, ms2, mus2, ns2).allMatch(JSRuntime::isIntegralNumber); - - TemporalUtil.Unit largestUnit1 = TemporalUtil.defaultTemporalLargestUnit(y1, mon1, w1, d1, h1, min1, s1, ms1, mus1); - TemporalUtil.Unit largestUnit2 = TemporalUtil.defaultTemporalLargestUnit(y2, mon2, w2, d2, h2, min2, s2, ms2, mus2); - TemporalUtil.Unit largestUnit = TemporalUtil.largerOfTwoTemporalUnits(largestUnit1, largestUnit2); - JSContext ctx = getLanguage().getJSContext(); - JSRealm realm = getRealm(); - if (relativeTo == null) { - relativeToUndefinedBranch.enter(this); - if (largestUnit == TemporalUtil.Unit.YEAR || largestUnit == TemporalUtil.Unit.MONTH || largestUnit == TemporalUtil.Unit.WEEK) { - errorBranch.enter(this); - throw Errors.createRangeError("Largest unit allowed with no relativeTo is 'days'."); - } - var result = TemporalUtil.balanceTimeDuration(d1 + d2, h1 + h2, min1 + min2, s1 + s2, ms1 + ms2, mus1 + mus2, ns1 + ns2, largestUnit); - return TemporalUtil.createDurationRecord(0, 0, 0, result.days(), result.hours(), result.minutes(), result.seconds(), result.milliseconds(), result.microseconds(), result.nanoseconds()); - } else if (relativeTo instanceof JSTemporalPlainDateObject plainRelativeTo) { - relativeToPlainDateBranch.enter(this); - var dateDuration1 = JSTemporalDuration.createTemporalDuration(ctx, realm, y1, mon1, w1, d1, 0, 0, 0, 0, 0, 0, this, errorBranch); - var dateDuration2 = JSTemporalDuration.createTemporalDuration(ctx, realm, y2, mon2, w2, d2, 0, 0, 0, 0, 0, 0, this, errorBranch); - - JSTemporalPlainDateObject intermediate = addDateNode.execute(calendarRec, plainRelativeTo, dateDuration1, Undefined.instance); - JSTemporalPlainDateObject end = addDateNode.execute(calendarRec, intermediate, dateDuration2, Undefined.instance); - - TemporalUtil.Unit dateLargestUnit = TemporalUtil.largerOfTwoTemporalUnits(TemporalUtil.Unit.DAY, largestUnit); - - JSObject differenceOptions = JSOrdinary.createWithNullPrototype(ctx); - JSObjectUtil.putDataProperty(differenceOptions, LARGEST_UNIT, dateLargestUnit.toTruffleString()); - JSTemporalDurationObject dateDifference = differenceDateNode.execute(calendarRec, plainRelativeTo, end, largestUnit, differenceOptions); - var result = TemporalUtil.balanceTimeDuration(dateDifference.getDays(), - h1 + h2, min1 + min2, s1 + s2, ms1 + ms2, mus1 + mus2, ns1 + ns2, largestUnit); - return TemporalUtil.createDurationRecord(dateDifference.getYears(), dateDifference.getMonths(), dateDifference.getWeeks(), result.days(), - result.hours(), result.minutes(), result.seconds(), result.milliseconds(), result.microseconds(), result.nanoseconds()); - } else if (relativeTo instanceof JSTemporalZonedDateTimeObject zonedRelativeTo) { - relativeToZonedDateTimeBranch.enter(this); - BigInt intermediateNs = TemporalUtil.addZonedDateTime(ctx, realm, zonedRelativeTo.getNanoseconds(), timeZoneRec, calendarRec, - dtol(y1), dtol(mon1), dtol(w1), dtol(d1), dtol(h1), dtol(min1), dtol(s1), dtol(ms1), dtol(mus1), dtol(ns1), precalculatedPlainDateTime); - BigInt endNs = TemporalUtil.addZonedDateTime(ctx, realm, intermediateNs, timeZoneRec, calendarRec, - dtol(y2), dtol(mon2), dtol(w2), dtol(d2), dtol(h2), dtol(min2), dtol(s2), dtol(ms2), dtol(mus2), dtol(ns2), precalculatedPlainDateTime); - if (largetUnitYMWDProfile.profile(this, - TemporalUtil.Unit.YEAR != largestUnit && TemporalUtil.Unit.MONTH != largestUnit && TemporalUtil.Unit.WEEK != largestUnit && TemporalUtil.Unit.DAY != largestUnit)) { - TimeDurationRecord result = TemporalUtil.differenceInstant(zonedRelativeTo.getNanoseconds(), endNs, 1, - TemporalUtil.Unit.NANOSECOND, largestUnit, TemporalUtil.RoundingMode.HALF_EXPAND, roundDurationNode); - return TemporalUtil.createDurationRecord(0, 0, 0, 0, result.hours(), result.minutes(), result.seconds(), result.milliseconds(), result.microseconds(), result.nanoseconds()); - } else { - return TemporalUtil.differenceZonedDateTime(ctx, realm, namesNode, zonedRelativeTo.getNanoseconds(), endNs, timeZoneRec, calendarRec, largestUnit, precalculatedPlainDateTime); - } - } else { - throw Errors.shouldNotReachHereUnexpectedValue(relativeTo); - } - } -} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalRoundDurationNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalRoundDurationNode.java deleted file mode 100644 index 89f7c9ad8a3..00000000000 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalRoundDurationNode.java +++ /dev/null @@ -1,413 +0,0 @@ -/* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * The Universal Permissive License (UPL), Version 1.0 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or - * data (collectively the "Software"), free of charge and under any and all - * copyright rights in the Software, and any and all patent rights owned or - * freely licensable by each licensor hereunder covering either (i) the - * unmodified Software as contributed to or provided by such licensor, or (ii) - * the Larger Works (as defined below), to deal in both - * - * (a) the Software, and - * - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * - * The above copyright notice and either this complete permission notice or at a - * minimum a reference to the UPL must be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.oracle.truffle.js.nodes.temporal; - -import static com.oracle.truffle.js.runtime.util.TemporalConstants.LARGEST_UNIT; -import static com.oracle.truffle.js.runtime.util.TemporalUtil.dtol; - -import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.profiles.InlinedBranchProfile; -import com.oracle.truffle.api.profiles.InlinedConditionProfile; -import com.oracle.truffle.js.nodes.JavaScriptBaseNode; -import com.oracle.truffle.js.runtime.BigInt; -import com.oracle.truffle.js.runtime.Errors; -import com.oracle.truffle.js.runtime.JSContext; -import com.oracle.truffle.js.runtime.JSRealm; -import com.oracle.truffle.js.runtime.JSRuntime; -import com.oracle.truffle.js.runtime.builtins.JSOrdinary; -import com.oracle.truffle.js.runtime.builtins.temporal.CalendarMethodsRecord; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDuration; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationRecord; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDate; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateObject; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateTimeObject; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalZonedDateTimeObject; -import com.oracle.truffle.js.runtime.builtins.temporal.MoveRelativeDateResult; -import com.oracle.truffle.js.runtime.builtins.temporal.NormalizedTimeDurationToDaysResult; -import com.oracle.truffle.js.runtime.builtins.temporal.TimeZoneMethodsRecord; -import com.oracle.truffle.js.runtime.objects.JSDynamicObject; -import com.oracle.truffle.js.runtime.objects.JSObject; -import com.oracle.truffle.js.runtime.objects.Undefined; -import com.oracle.truffle.js.runtime.util.TemporalErrors; -import com.oracle.truffle.js.runtime.util.TemporalUtil; -import com.oracle.truffle.js.runtime.util.TemporalUtil.Overflow; -import com.oracle.truffle.js.runtime.util.TemporalUtil.Unit; - -/** - * Implementation of the RoundDuration operation. - */ -public abstract class TemporalRoundDurationNode extends JavaScriptBaseNode { - - protected TemporalRoundDurationNode() { - } - - public final JSTemporalDurationRecord execute(double y, double m, double w, double d, double h, double min, - double sec, double milsec, double micsec, double nsec, int increment, - TemporalUtil.Unit unit, TemporalUtil.RoundingMode roundingMode) { - return execute(y, m, w, d, h, min, sec, milsec, micsec, nsec, increment, unit, roundingMode, - null, null, null, null, null); - } - - public final JSTemporalDurationRecord execute(double y, double m, double w, double d, double h, double min, - double sec, double milsec, double micsec, double nsec, int increment, - TemporalUtil.Unit unit, TemporalUtil.RoundingMode roundingMode, - JSTemporalPlainDateObject plainRelativeTo, - CalendarMethodsRecord calendarRec) { - return execute(y, m, w, d, h, min, sec, milsec, micsec, nsec, increment, unit, roundingMode, - plainRelativeTo, null, calendarRec, null, null); - } - - public abstract JSTemporalDurationRecord execute(double y, double m, double w, double d, double h, double min, - double sec, double milsec, double micsec, double nsec, int increment, - TemporalUtil.Unit unit, TemporalUtil.RoundingMode roundingMode, - JSTemporalPlainDateObject plainRelativeTo, JSTemporalZonedDateTimeObject zonedRelativeTo, - CalendarMethodsRecord calendarRec, TimeZoneMethodsRecord timeZoneRec, - JSTemporalPlainDateTimeObject precalculatedPlainDateTime); - - // @Cached parameters create unused variable in generated code, see GR-37931 - @Specialization - protected JSTemporalDurationRecord round(double years, double months, double weeks, double d, double h, double min, - double sec, double milsec, double micsec, double nsec, int increment, - TemporalUtil.Unit unit, TemporalUtil.RoundingMode roundingMode, - JSTemporalPlainDateObject plainRelativeTo, JSTemporalZonedDateTimeObject zonedRelativeTo, - CalendarMethodsRecord calendarRec, TimeZoneMethodsRecord timeZoneRec, - JSTemporalPlainDateTimeObject precalculatedPlainDateTime, - @Cached TemporalDifferenceDateNode differenceDateNode, - @Cached InlinedBranchProfile errorBranch, - @Cached InlinedConditionProfile unitYMWD, - @Cached InlinedBranchProfile yearBranch, - @Cached InlinedBranchProfile monthBranch, - @Cached InlinedBranchProfile weekBranch, - @Cached InlinedBranchProfile dayOrLessBranch, - @Cached TemporalMoveRelativeDateNode moveRelativeDateNode) { - assert plainRelativeTo == null && zonedRelativeTo == null || calendarRec != null && calendarRec.dateAdd() != null && calendarRec.dateUntil() != null; - - double days = d; - double hours = h; - double minutes = min; - double seconds = sec; - double microseconds = micsec; - double milliseconds = milsec; - double nanoseconds = nsec; - - if ((unit == Unit.YEAR || unit == Unit.MONTH || unit == Unit.WEEK) && plainRelativeTo == null) { - errorBranch.enter(this); - throw TemporalErrors.createRangeErrorRelativeToNotUndefined(unit); - } - JSContext ctx = getLanguage().getJSContext(); - JSRealm realm = getRealm(); - - double fractionalSeconds; - if (unitYMWD.profile(this, unit == Unit.YEAR || unit == Unit.MONTH || unit == Unit.WEEK || unit == Unit.DAY)) { - BigInt totalNs = TemporalUtil.totalDurationNanoseconds(0, hours, minutes, seconds, milliseconds, microseconds, nanoseconds); - JSTemporalZonedDateTimeObject intermediate = null; - if (zonedRelativeTo != null) { - intermediate = TemporalUtil.moveRelativeZonedDateTime(ctx, realm, zonedRelativeTo, calendarRec, timeZoneRec, dtol(years), dtol(months), dtol(weeks), dtol(days), - precalculatedPlainDateTime); - NormalizedTimeDurationToDaysResult result = TemporalUtil.normalizedTimeDurationToDays(ctx, realm, totalNs, intermediate, timeZoneRec); - days = calculateDays(days, result); - } else { - days = days + nanoseconds / TemporalUtil.NS_PER_DAY; - } - hours = 0; - minutes = 0; - seconds = 0; - milliseconds = 0; - microseconds = 0; - nanoseconds = 0; - fractionalSeconds = 0; // fractionalSeconds is not used below. - } else { - fractionalSeconds = TemporalUtil.roundDurationCalculateFractionalSeconds(seconds, milliseconds, microseconds, nanoseconds); - } - switch (unit) { - case YEAR: - yearBranch.enter(this); - return getUnitYear(increment, roundingMode, years, months, weeks, days, hours, minutes, seconds, microseconds, milliseconds, nanoseconds, - plainRelativeTo, calendarRec, - moveRelativeDateNode, differenceDateNode, this, dayOrLessBranch); - case MONTH: - monthBranch.enter(this); - return getUnitMonth(increment, roundingMode, years, months, weeks, days, hours, minutes, seconds, microseconds, milliseconds, nanoseconds, - plainRelativeTo, calendarRec, - moveRelativeDateNode, differenceDateNode, this, dayOrLessBranch); - case WEEK: - weekBranch.enter(this); - return getUnitWeek(increment, roundingMode, years, months, weeks, days, hours, minutes, seconds, microseconds, milliseconds, nanoseconds, - plainRelativeTo, calendarRec, - moveRelativeDateNode, differenceDateNode, this, dayOrLessBranch); - case DAY: - dayOrLessBranch.enter(this); - return getUnitDay(increment, roundingMode, years, months, weeks, days, hours, minutes, seconds, microseconds, milliseconds, nanoseconds); - case HOUR: - dayOrLessBranch.enter(this); - return getUnitHour(increment, roundingMode, years, months, weeks, days, hours, minutes, fractionalSeconds); - case MINUTE: - dayOrLessBranch.enter(this); - return getUnitMinute(increment, roundingMode, years, months, weeks, days, hours, minutes, fractionalSeconds); - case SECOND: - dayOrLessBranch.enter(this); - return getUnitSecond(increment, roundingMode, years, months, weeks, days, hours, minutes, fractionalSeconds); - case MILLISECOND: - dayOrLessBranch.enter(this); - return getUnitMillisecond(increment, roundingMode, years, months, weeks, days, hours, minutes, seconds, microseconds, milliseconds, nanoseconds); - case MICROSECOND: - dayOrLessBranch.enter(this); - return getUnitMicrosecond(increment, roundingMode, years, months, weeks, days, hours, minutes, seconds, microseconds, milliseconds, nanoseconds); - case NANOSECOND: - dayOrLessBranch.enter(this); - return getUnitNanosecond(increment, roundingMode, years, months, weeks, days, hours, minutes, seconds, microseconds, milliseconds, nanoseconds); - } - throw Errors.shouldNotReachHere(); - } - - private static JSTemporalDurationRecord getUnitNanosecond(int increment, TemporalUtil.RoundingMode roundingMode, final double years, final double months, final double weeks, final double days, - final double hours, final double minutes, final double seconds, final double microseconds, final double milliseconds, final double nanosecondsP) { - double nanoseconds = nanosecondsP; - double remainder = nanoseconds; - nanoseconds = TemporalUtil.roundNumberToIncrement(nanoseconds, increment, roundingMode); - remainder = remainder - nanoseconds; - return JSTemporalDurationRecord.createWeeksRemainder(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, remainder); - } - - private static JSTemporalDurationRecord getUnitMicrosecond(int increment, TemporalUtil.RoundingMode roundingMode, final double years, final double months, final double weeks, final double days, - final double hours, final double minutes, final double seconds, final double microsecondsP, final double milliseconds, final double nanoseconds) { - double microseconds = microsecondsP; - double fractionalMicroseconds = (nanoseconds * 0.001) + microseconds; - microseconds = TemporalUtil.roundNumberToIncrement(fractionalMicroseconds, increment, roundingMode); - double remainder = fractionalMicroseconds - microseconds; - return JSTemporalDurationRecord.createWeeksRemainder(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, 0, remainder); - } - - private static JSTemporalDurationRecord getUnitMillisecond(int increment, TemporalUtil.RoundingMode roundingMode, final double years, final double months, final double weeks, final double days, - final double hours, final double minutes, final double seconds, final double microseconds, final double millisecondsP, final double nanoseconds) { - double milliseconds = millisecondsP; - double fractionalMilliseconds = (nanoseconds * 0.000_001) + (microseconds * 0.001) + milliseconds; - milliseconds = TemporalUtil.roundNumberToIncrement(fractionalMilliseconds, increment, roundingMode); - double remainder = fractionalMilliseconds - milliseconds; - return JSTemporalDurationRecord.createWeeksRemainder(years, months, weeks, days, hours, minutes, seconds, milliseconds, 0, 0, remainder); - } - - private static JSTemporalDurationRecord getUnitMinute(int increment, TemporalUtil.RoundingMode roundingMode, final double years, final double months, final double weeks, final double days, - final double hours, final double minutesP, double fractionalSeconds) { - double minutes = minutesP; - double fractionalMinutes = (fractionalSeconds / 60) + minutes; - minutes = TemporalUtil.roundNumberToIncrement(fractionalMinutes, increment, roundingMode); - double remainder = fractionalMinutes - minutes; - return JSTemporalDurationRecord.createWeeksRemainder(years, months, weeks, days, hours, minutes, 0, 0, 0, 0, remainder); - } - - private static JSTemporalDurationRecord getUnitHour(int increment, TemporalUtil.RoundingMode roundingMode, final double years, final double months, final double weeks, final double days, - final double hoursP, final double minutes, double fractionalSeconds) { - double hours = hoursP; - double fractionalHours = (((fractionalSeconds / 60) + minutes) / 60) + hours; - hours = TemporalUtil.roundNumberToIncrement(fractionalHours, increment, roundingMode); - double remainder = fractionalHours - hours; - return JSTemporalDurationRecord.createWeeksRemainder(years, months, weeks, days, hours, 0, 0, 0, 0, 0, remainder); - } - - private static JSTemporalDurationRecord getUnitDay(int increment, TemporalUtil.RoundingMode roundingMode, final double years, final double months, final double weeks, final double daysP, - final double hours, final double minutes, final double seconds, final double microseconds, final double milliseconds, final double nanoseconds) { - double fractionalDays = daysP; - double days = TemporalUtil.roundNumberToIncrement(daysP, increment, roundingMode); - double remainder = fractionalDays - days; - return JSTemporalDurationRecord.createWeeksRemainder(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, remainder); - } - - private JSTemporalDurationRecord getUnitWeek(int increment, TemporalUtil.RoundingMode roundingMode, - final double years, final double months, final double weeksP, final double daysP, - final double hours, final double minutes, final double seconds, final double microseconds, final double milliseconds, final double nanoseconds, - JSTemporalPlainDateObject relativeToP, CalendarMethodsRecord calendarRec, - TemporalMoveRelativeDateNode moveRelativeDateNode, TemporalDifferenceDateNode differenceDateNode, Node node, InlinedBranchProfile errorBranch) { - double weeks = weeksP; - double fractionalDays = daysP; - JSTemporalPlainDateObject relativeTo = relativeToP; - JSContext ctx = getLanguage().getJSContext(); - JSRealm realm = getRealm(); - - var isoResult = TemporalUtil.addISODate(relativeTo.getYear(), relativeTo.getMonth(), relativeTo.getDay(), - 0, 0, 0, JSRuntime.truncateDouble(fractionalDays), Overflow.CONSTRAIN); - var wholeDaysLater = JSTemporalPlainDate.create(ctx, getRealm(), isoResult.year(), isoResult.month(), isoResult.day(), calendarRec.receiver(), node, errorBranch); - var untilOptions = createUntilOptions(Unit.WEEK); - var timePassed = differenceDateNode.execute(calendarRec, relativeTo, wholeDaysLater, Unit.WEEK, untilOptions); - var weeksPassed = timePassed.getWeeks(); - weeks += weeksPassed; - - var weeksPassedDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, 0, 0, weeksPassed, 0, 0, 0, 0, 0, 0, 0, this, errorBranch); - var moveResult = moveRelativeDateNode.execute(calendarRec, relativeTo, weeksPassedDuration); - relativeTo = moveResult.relativeTo(); - double daysPassed = moveResult.days(); - fractionalDays -= daysPassed; - - double sign = fractionalDays < 0 ? -1 : 1; - var oneWeek = JSTemporalDuration.createTemporalDuration(ctx, realm, 0, 0, sign, 0, 0, 0, 0, 0, 0, 0, node, errorBranch); - moveResult = moveRelativeDateNode.execute(calendarRec, relativeTo, oneWeek); - double oneWeekDays = moveResult.days(); - if (oneWeekDays == 0) { - errorBranch.enter(node); - throw Errors.createRangeError("dateAdd of one week moved date by 0 days"); - } - - double fractionalWeeks = weeks + (fractionalDays / Math.abs(oneWeekDays)); - weeks = TemporalUtil.roundNumberToIncrement(fractionalWeeks, increment, roundingMode); - double remainder = fractionalWeeks - weeks; - return JSTemporalDurationRecord.createWeeksRemainder(years, months, weeks, 0, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, remainder); - } - - private JSTemporalDurationRecord getUnitMonth(int increment, TemporalUtil.RoundingMode roundingMode, - final double years, final double monthsP, final double weeks, final double daysP, - final double hours, final double minutes, final double seconds, final double microseconds, final double milliseconds, final double nanoseconds, - JSTemporalPlainDateObject relativeToP, CalendarMethodsRecord calendarRec, - TemporalMoveRelativeDateNode moveRelativeDateNode, TemporalDifferenceDateNode differenceDateNode, Node node, InlinedBranchProfile errorBranch) { - double months = monthsP; - double fractionalDays = daysP; - JSTemporalPlainDateObject relativeTo = relativeToP; - JSContext ctx = getLanguage().getJSContext(); - JSRealm realm = getRealm(); - - JSDynamicObject yearsMonths = JSTemporalDuration.createTemporalDuration(ctx, realm, years, months, 0, 0, 0, 0, 0, 0, 0, 0, node, errorBranch); - JSTemporalPlainDateObject yearsMonthsLater = TemporalUtil.calendarDateAdd(calendarRec, relativeTo, yearsMonths, Undefined.instance); - JSDynamicObject yearsMonthsWeeks = JSTemporalDuration.createTemporalDuration(ctx, realm, years, months, weeks, 0, 0, 0, 0, 0, 0, 0, node, errorBranch); - JSTemporalPlainDateObject yearsMonthsWeeksLater = TemporalUtil.calendarDateAdd(calendarRec, relativeTo, yearsMonthsWeeks, Undefined.instance); - double weeksInDays = TemporalUtil.daysUntil(yearsMonthsLater, yearsMonthsWeeksLater); - relativeTo = yearsMonthsLater; - fractionalDays = fractionalDays + weeksInDays; - - var isoResult = TemporalUtil.addISODate(relativeTo.getYear(), relativeTo.getMonth(), relativeTo.getDay(), - 0, 0, 0, JSRuntime.truncateDouble(fractionalDays), Overflow.CONSTRAIN); - var wholeDaysLater = JSTemporalPlainDate.create(ctx, getRealm(), isoResult.year(), isoResult.month(), isoResult.day(), calendarRec.receiver(), node, errorBranch); - var untilOptions = createUntilOptions(Unit.MONTH); - var timePassed = differenceDateNode.execute(calendarRec, relativeTo, wholeDaysLater, Unit.MONTH, untilOptions); - var monthsPassed = timePassed.getMonths(); - months += monthsPassed; - - var monthsPassedDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, 0, monthsPassed, 0, 0, 0, 0, 0, 0, 0, 0, node, errorBranch); - MoveRelativeDateResult moveResult = moveRelativeDateNode.execute(calendarRec, relativeTo, monthsPassedDuration); - relativeTo = moveResult.relativeTo(); - double daysPassed = moveResult.days(); - fractionalDays -= daysPassed; - - double sign = fractionalDays < 0 ? -1 : 1; - var oneMonth = JSTemporalDuration.createTemporalDuration(ctx, realm, 0, sign, 0, 0, 0, 0, 0, 0, 0, 0, node, errorBranch); - moveResult = moveRelativeDateNode.execute(calendarRec, relativeTo, oneMonth); - double oneMonthDays = moveResult.days(); - if (oneMonthDays == 0) { - errorBranch.enter(node); - throw Errors.createRangeError("dateAdd of one month moved date by 0 days"); - } - - double fractionalMonths = months + (fractionalDays / Math.abs(oneMonthDays)); - months = TemporalUtil.roundNumberToIncrement(fractionalMonths, increment, roundingMode); - double remainder = fractionalMonths - months; - return JSTemporalDurationRecord.createWeeksRemainder(years, months, 0, 0, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, remainder); - } - - @TruffleBoundary - private static JSTemporalDurationRecord getUnitSecond(int increment, TemporalUtil.RoundingMode roundingMode, - double years, double months, double weeks, double days, - double hours, double minutes, double fractionalSeconds) { - double seconds = TemporalUtil.roundNumberToIncrement(fractionalSeconds, increment, roundingMode); - double remainder = fractionalSeconds - seconds; - return JSTemporalDurationRecord.createWeeksRemainder(years, months, weeks, days, hours, minutes, seconds, 0, 0, 0, remainder); - } - - private JSTemporalDurationRecord getUnitYear(final int increment, TemporalUtil.RoundingMode roundingMode, - final double yearsP, final double months, final double weeks, final double daysP, - final double hours, final double minutes, final double seconds, final double microseconds, final double milliseconds, final double nanoseconds, - JSTemporalPlainDateObject relativeToP, CalendarMethodsRecord calendarRec, - TemporalMoveRelativeDateNode moveRelativeDateNode, TemporalDifferenceDateNode differenceDateNode, Node node, InlinedBranchProfile errorBranch) { - double years = yearsP; - double fractionalDays = daysP; - JSTemporalPlainDateObject relativeTo = relativeToP; - JSContext ctx = getLanguage().getJSContext(); - JSRealm realm = getRealm(); - - var yearsDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, years, 0, 0, 0, 0, 0, 0, 0, 0, 0, node, errorBranch); - var yearsLater = TemporalUtil.calendarDateAdd(calendarRec, relativeTo, yearsDuration); - var yearsMonthsWeeks = JSTemporalDuration.createTemporalDuration(ctx, realm, years, months, weeks, 0, 0, 0, 0, 0, 0, 0, node, errorBranch); - var yearsMonthsWeeksLater = TemporalUtil.calendarDateAdd(calendarRec, relativeTo, yearsMonthsWeeks); - double monthsWeeksInDays = TemporalUtil.daysUntil(yearsLater, yearsMonthsWeeksLater); - relativeTo = yearsLater; - fractionalDays += monthsWeeksInDays; - - var isoResult = TemporalUtil.addISODate(relativeTo.getYear(), relativeTo.getMonth(), relativeTo.getDay(), - 0, 0, 0, JSRuntime.truncateDouble(fractionalDays), Overflow.CONSTRAIN); - var wholeDaysLater = JSTemporalPlainDate.create(ctx, getRealm(), isoResult.year(), isoResult.month(), isoResult.day(), calendarRec.receiver(), node, errorBranch); - var untilOptions = createUntilOptions(Unit.YEAR); - var timePassed = differenceDateNode.execute(calendarRec, relativeTo, wholeDaysLater, Unit.YEAR, untilOptions); - var yearsPassed = timePassed.getYears(); - years += yearsPassed; - - var yearsPassedDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, yearsPassed, 0, 0, 0, 0, 0, 0, 0, 0, 0, node, errorBranch); - MoveRelativeDateResult moveResult = moveRelativeDateNode.execute(calendarRec, relativeTo, yearsPassedDuration); - relativeTo = moveResult.relativeTo(); - double daysPassed = moveResult.days(); - fractionalDays -= daysPassed; - - double sign = fractionalDays < 0 ? -1 : 1; - var oneYear = JSTemporalDuration.createTemporalDuration(ctx, realm, sign, 0, 0, 0, 0, 0, 0, 0, 0, 0, node, errorBranch); - moveResult = moveRelativeDateNode.execute(calendarRec, relativeTo, oneYear); - double oneYearDays = moveResult.days(); - if (oneYearDays == 0) { - errorBranch.enter(node); - throw Errors.createRangeError("dateAdd of one year moved date by 0 days"); - } - - double fractionalYears = years + (fractionalDays / Math.abs(oneYearDays)); - years = TemporalUtil.roundNumberToIncrement(fractionalYears, increment, roundingMode); - double remainder = fractionalYears - years; - return JSTemporalDurationRecord.createWeeksRemainder(years, 0, 0, 0, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, remainder); - } - - private JSObject createUntilOptions(Unit largestUnit) { - JSContext ctx = getLanguage().getJSContext(); - JSObject untilOptions = JSOrdinary.createWithNullPrototype(ctx); - TemporalUtil.createDataPropertyOrThrow(ctx, untilOptions, LARGEST_UNIT, largestUnit.toTruffleString()); - return untilOptions; - } - - @TruffleBoundary - private static double calculateDays(double days, NormalizedTimeDurationToDaysResult result) { - return days + TemporalUtil.bitod(result.days().add(result.remainder().divide(result.dayLength().abs()))); - } -} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalUnbalanceDateDurationRelativeNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalUnbalanceDateDurationRelativeNode.java index 76fbc068992..bfbfef0af92 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalUnbalanceDateDurationRelativeNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalUnbalanceDateDurationRelativeNode.java @@ -40,29 +40,20 @@ */ package com.oracle.truffle.js.nodes.temporal; -import static com.oracle.truffle.js.runtime.util.TemporalConstants.LARGEST_UNIT; -import static com.oracle.truffle.js.runtime.util.TemporalConstants.MONTH; - -import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; -import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.js.nodes.JavaScriptBaseNode; import com.oracle.truffle.js.nodes.function.JSFunctionCallNode; -import com.oracle.truffle.js.runtime.Errors; import com.oracle.truffle.js.runtime.JSArguments; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRealm; -import com.oracle.truffle.js.runtime.builtins.JSOrdinary; import com.oracle.truffle.js.runtime.builtins.temporal.CalendarMethodsRecord; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDuration; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationObject; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationRecord; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateObject; -import com.oracle.truffle.js.runtime.objects.JSDynamicObject; -import com.oracle.truffle.js.runtime.objects.JSObjectUtil; +import com.oracle.truffle.js.runtime.objects.Undefined; import com.oracle.truffle.js.runtime.util.TemporalUtil; /** @@ -70,125 +61,39 @@ */ public abstract class TemporalUnbalanceDateDurationRelativeNode extends JavaScriptBaseNode { - @Child private ToTemporalCalendarObjectNode toCalendarObjectNode; - @Child private JSFunctionCallNode callDateAddNode; - @Child private JSFunctionCallNode callDateUntilNode; - protected TemporalUnbalanceDateDurationRelativeNode() { } - public abstract JSTemporalDurationRecord execute(double year, double month, double week, double day, TemporalUtil.Unit largestUnit, + public abstract double execute(double year, double month, double week, double day, JSTemporalPlainDateObject plainRelativeTo, CalendarMethodsRecord calendarRec); @Specialization - protected JSTemporalDurationRecord unbalanceDurationRelative(double years, double months, double weeks, double days, TemporalUtil.Unit largestUnit, + protected double unbalanceDurationRelative(double years, double months, double weeks, double days, JSTemporalPlainDateObject plainRelativeTo, CalendarMethodsRecord calendarRec, - @Cached InlinedBranchProfile errorBranch, - @Cached InlinedConditionProfile unitIsYear, - @Cached InlinedConditionProfile unitIsWeek, - @Cached InlinedConditionProfile unitIsMonth) { - assert plainRelativeTo == null || calendarRec != null; - - if (unitIsYear.profile(this, TemporalUtil.Unit.YEAR == largestUnit)) { - return JSTemporalDurationRecord.createWeeks(years, months, weeks, days, 0, 0, 0, 0, 0, 0); - } - - JSContext ctx = getLanguage().getJSContext(); - JSRealm realm = getRealm(); - if (unitIsMonth.profile(this, TemporalUtil.Unit.MONTH == largestUnit)) { - return unitIsMonth(ctx, realm, years, months, weeks, days, plainRelativeTo, calendarRec, this, errorBranch); - } else if (unitIsWeek.profile(this, TemporalUtil.Unit.WEEK == largestUnit)) { - return unitIsWeek(ctx, realm, years, months, weeks, days, plainRelativeTo, calendarRec, this, errorBranch); - } else { - return unitIsDay(ctx, realm, years, months, weeks, days, plainRelativeTo, calendarRec, this, errorBranch); - } - } + @Cached ToTemporalCalendarObjectNode toCalendarObjectNode, + @Cached("createCall()") JSFunctionCallNode callDateAddNode, + @Cached InlinedBranchProfile errorBranch) { + assert plainRelativeTo != null && calendarRec != null && calendarRec.dateAdd() != null; - private JSTemporalDurationRecord unitIsDay(JSContext ctx, JSRealm realm, double years, double months, double weeks, double days, JSTemporalPlainDateObject plainRelativeTo, - CalendarMethodsRecord calendarRec, Node node, InlinedBranchProfile errorBranch) { if (years == 0 && months == 0 && weeks == 0) { - return JSTemporalDurationRecord.createWeeks(0, 0, 0, days, 0, 0, 0, 0, 0, 0); + return days; } - checkCalendar(calendarRec, this, errorBranch); - assert calendarRec.dateAdd() != null; + JSContext ctx = getJSContext(); + JSRealm realm = getRealm(); var yearsMonthsWeeksDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, years, months, weeks, 0, 0, 0, 0, 0, 0, 0, this, errorBranch); - JSTemporalPlainDateObject later = calendarDateAdd(calendarRec, plainRelativeTo, yearsMonthsWeeksDuration, node, errorBranch); + JSTemporalPlainDateObject later = calendarDateAdd(calendarRec, plainRelativeTo, yearsMonthsWeeksDuration, + this, errorBranch, toCalendarObjectNode, callDateAddNode); double yearsMonthsWeeksInDays = TemporalUtil.daysUntil(plainRelativeTo, later); - - return JSTemporalDurationRecord.createWeeks(0, 0, 0, days + yearsMonthsWeeksInDays, 0, 0, 0, 0, 0, 0); - } - - private JSTemporalDurationRecord unitIsWeek(JSContext ctx, JSRealm realm, double years, double months, double weeks, double days, JSTemporalPlainDateObject plainRelativeTo, - CalendarMethodsRecord calendarRec, Node node, InlinedBranchProfile errorBranch) { - if (years == 0 && months == 0) { - return JSTemporalDurationRecord.createWeeks(0, 0, weeks, days, 0, 0, 0, 0, 0, 0); - } - - checkCalendar(calendarRec, this, errorBranch); - assert calendarRec.dateAdd() != null; - - var yearsMonthsDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, years, months, 0, 0, 0, 0, 0, 0, 0, 0, this, errorBranch); - JSTemporalPlainDateObject later = calendarDateAdd(calendarRec, plainRelativeTo, yearsMonthsDuration, node, errorBranch); - double yearsMonthsInDays = TemporalUtil.daysUntil(plainRelativeTo, later); - - return JSTemporalDurationRecord.createWeeks(0, 0, weeks, days + yearsMonthsInDays, 0, 0, 0, 0, 0, 0); + return days + yearsMonthsWeeksInDays; } - private JSTemporalDurationRecord unitIsMonth(JSContext ctx, JSRealm realm, double years, double months, double weeks, double days, JSTemporalPlainDateObject plainRelativeTo, - CalendarMethodsRecord calendarRec, Node node, InlinedBranchProfile errorBranch) { - if (years == 0) { - return JSTemporalDurationRecord.createWeeks(0, months, weeks, days, 0, 0, 0, 0, 0, 0); - } - - checkCalendar(calendarRec, this, errorBranch); - assert calendarRec.dateAdd() != null && calendarRec.dateUntil() != null; - - var yearsDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, years, 0, 0, 0, 0, 0, 0, 0, 0, 0, this, errorBranch); - JSTemporalPlainDateObject later = calendarDateAdd(calendarRec, plainRelativeTo, yearsDuration, node, errorBranch); - JSDynamicObject untilOptions = JSOrdinary.createWithNullPrototype(ctx); - JSObjectUtil.putDataProperty(untilOptions, LARGEST_UNIT, MONTH); - JSTemporalDurationObject untilResult = calendarDateUntil(calendarRec, plainRelativeTo, later, untilOptions); - double yearsInMonths = untilResult.getMonths(); - - return JSTemporalDurationRecord.createWeeks(0, months + yearsInMonths, weeks, days, 0, 0, 0, 0, 0, 0); - } - - protected JSTemporalPlainDateObject calendarDateAdd(CalendarMethodsRecord calendarRec, JSDynamicObject date, JSDynamicObject duration, - Node node, InlinedBranchProfile errorBranch) { - if (callDateAddNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - callDateAddNode = insert(JSFunctionCallNode.createCall()); - } - Object calendar = toCalendarObject(calendarRec); - Object addedDate = callDateAddNode.executeCall(JSArguments.create(calendar, calendarRec.dateAdd(), date, duration)); + static JSTemporalPlainDateObject calendarDateAdd(CalendarMethodsRecord calendarRec, JSTemporalPlainDateObject date, JSTemporalDurationObject duration, + Node node, InlinedBranchProfile errorBranch, ToTemporalCalendarObjectNode toCalendarObjectNode, JSFunctionCallNode callDateAddNode) { + Object calendar = toCalendarObjectNode.execute(calendarRec.receiver()); + Object addedDate = callDateAddNode.executeCall(JSArguments.create(calendar, calendarRec.dateAdd(), date, duration, Undefined.instance)); return TemporalUtil.requireTemporalDate(addedDate, node, errorBranch); } - protected JSTemporalDurationObject calendarDateUntil(CalendarMethodsRecord calendarRec, JSDynamicObject date, JSDynamicObject duration, JSDynamicObject options) { - if (callDateUntilNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - callDateUntilNode = insert(JSFunctionCallNode.createCall()); - } - Object calendar = toCalendarObject(calendarRec); - Object addedDate = callDateUntilNode.executeCall(JSArguments.create(calendar, calendarRec.dateUntil(), date, duration, options)); - return TemporalUtil.requireTemporalDuration(addedDate); - } - - private Object toCalendarObject(CalendarMethodsRecord calendarRec) { - if (toCalendarObjectNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - toCalendarObjectNode = insert(ToTemporalCalendarObjectNode.create()); - } - return toCalendarObjectNode.execute(calendarRec.receiver()); - } - - private static void checkCalendar(CalendarMethodsRecord calendarRec, Node node, InlinedBranchProfile errorBranch) { - if (calendarRec == null) { - errorBranch.enter(node); - throw Errors.createRangeError("Calendar should not be undefined."); - } - } - } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/BigInt.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/BigInt.java index 7e8c1de61e9..b891f6218ab 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/BigInt.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/BigInt.java @@ -326,6 +326,12 @@ public BigInt remainder(BigInt b) { return new BigInt(value.remainder(b.value)); } + @TruffleBoundary + public BigInt[] divideAndRemainder(BigInt b) { + BigInteger[] qr = value.divideAndRemainder(b.value); + return new BigInt[]{new BigInt(qr[0]), new BigInt(qr[1])}; + } + @TruffleBoundary public BigInt shiftLeft(int b) { return new BigInt(value.shiftLeft(b)); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/ISODateTimeRecord.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/ISODateTimeRecord.java new file mode 100644 index 00000000000..d4b27666387 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/ISODateTimeRecord.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.runtime.builtins.temporal; + +/** + * An ISO Date-Time Record is used to represent a valid calendar date in the ISO 8601 calendar + * together with a clock time. + * + * @param year The year in the ISO 8601 calendar. An integer. + * @param month The number of the month. An integer between 1 and 12, inclusive. + * @param day The number of the day of the month. An integer between 1 and 31, inclusive. + * @param hour The number of the hour. An integer in the inclusive range 0 to 23. + * @param minute The number of the minute. An integer in the inclusive range 0 to 59. + * @param second The number of the second. An integer in the inclusive range 0 to 59. + * @param millisecond The number of the millisecond. An integer in the inclusive range 0 to 999. + * @param microsecond The number of the microsecond. An integer in the inclusive range 0 to 999. + * @param nanosecond The number of the nanosecond. An integer in the inclusive range 0 to 999. + */ +public record ISODateTimeRecord( + int year, + int month, + int day, + int hour, + int minute, + int second, + int millisecond, + int microsecond, + int nanosecond) { +} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/NormalizedDurationRecord.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/NormalizedDurationRecord.java new file mode 100644 index 00000000000..61a8389d1bb --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/NormalizedDurationRecord.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.runtime.builtins.temporal; + +import com.oracle.truffle.js.runtime.BigInt; + +/** + * Normalized Duration Record. + * + * @param years a float64-representable integer + * @param months a float64-representable integer + * @param weeks a float64-representable integer + * @param days a float64-representable integer + * @param normalizedTimeTotalNanoseconds a Normalized Time Duration Record (the time portion). + */ +public record NormalizedDurationRecord( + double years, + double months, + double weeks, + double days, + BigInt normalizedTimeTotalNanoseconds) { +} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/NormalizedTimeDurationToDaysResult.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/TemporalDurationWithTotalRecord.java similarity index 84% rename from graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/NormalizedTimeDurationToDaysResult.java rename to graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/TemporalDurationWithTotalRecord.java index fd9654baa41..ac2e94d8c94 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/NormalizedTimeDurationToDaysResult.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/TemporalDurationWithTotalRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -40,7 +40,11 @@ */ package com.oracle.truffle.js.runtime.builtins.temporal; -import java.math.BigInteger; - -public record NormalizedTimeDurationToDaysResult(BigInteger days, BigInteger remainder, BigInteger dayLength) { +/** + * The result record returned by the operations: RoundRelativeDuration, + * DifferencePlainDateTimeWithRounding, DifferenceZonedDateTimeWithRounding. + */ +public record TemporalDurationWithTotalRecord( + JSTemporalDurationRecord duration, + double total) { } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java index 64dac96e978..a0c1f23237a 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java @@ -113,7 +113,9 @@ import java.util.Set; import java.util.function.Function; +import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.ExactMath; import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff; @@ -128,9 +130,7 @@ import com.oracle.truffle.js.nodes.temporal.CalendarMethodsRecordLookupNode; import com.oracle.truffle.js.nodes.temporal.TemporalCalendarDateFromFieldsNode; import com.oracle.truffle.js.nodes.temporal.TemporalCalendarGetterNode; -import com.oracle.truffle.js.nodes.temporal.TemporalDurationAddNode; import com.oracle.truffle.js.nodes.temporal.TemporalGetOptionNode; -import com.oracle.truffle.js.nodes.temporal.TemporalRoundDurationNode; import com.oracle.truffle.js.nodes.temporal.ToFractionalSecondDigitsNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalCalendarIdentifierNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalCalendarSlotValueNode; @@ -148,6 +148,7 @@ import com.oracle.truffle.js.runtime.builtins.JSOrdinary; import com.oracle.truffle.js.runtime.builtins.intl.JSDateTimeFormat; import com.oracle.truffle.js.runtime.builtins.temporal.CalendarMethodsRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.DateDurationRecord; import com.oracle.truffle.js.runtime.builtins.temporal.ISODateRecord; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalCalendar; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalCalendarObject; @@ -168,7 +169,7 @@ import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalTimeZoneRecord; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalZonedDateTime; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalZonedDateTimeObject; -import com.oracle.truffle.js.runtime.builtins.temporal.NormalizedTimeDurationToDaysResult; +import com.oracle.truffle.js.runtime.builtins.temporal.NormalizedDurationRecord; import com.oracle.truffle.js.runtime.builtins.temporal.ParseISODateTimeResult; import com.oracle.truffle.js.runtime.builtins.temporal.TimeDurationRecord; import com.oracle.truffle.js.runtime.builtins.temporal.TimeRecord; @@ -276,23 +277,31 @@ public final class TemporalUtil { public static final TruffleString[] TIME_LIKE_PROPERTIES = new TruffleString[]{HOUR, MICROSECOND, MILLISECOND, MINUTE, NANOSECOND, SECOND}; - private static final BigInt upperEpochNSLimit = new BigInt(BigInteger.valueOf(86400).multiply(BigInteger.valueOf(10).pow(17))); + public static final int MS_PER_DAY = 86_400_000; // 24 * 60 * 60 * 1000 + public static final long NS_PER_DAY_LONG = 1_000_000L * MS_PER_DAY; + public static final double NS_PER_DAY = NS_PER_DAY_LONG; // 8.64e13 + public static final BigInt BI_NS_PER_DAY = BigInt.valueOf(NS_PER_DAY_LONG); + + /** Instant range is 100 million days (inclusive) before or after epoch (~273,790 years). */ + private static final int INSTANT_MAX_OFFSET_EPOCH_DAYS = 100_000_000; // 10**8 + /** nsMaxInstant (inclusive) = 10**8 * nsPerDay = 8.64 * 10**21. */ + private static final BigInt upperEpochNSLimit = BI_NS_PER_DAY.multiply(BigInt.valueOf(INSTANT_MAX_OFFSET_EPOCH_DAYS)); + /** nsMinInstant (inclusive) = -nsMaxInstant = -8.64 * 10**21. */ private static final BigInt lowerEpochNSLimit = upperEpochNSLimit.negate(); - - // 8.64* 10^21 + 8.64 * 10^13; roughly 273,000 years - private static final BigInteger isoTimeUpperBound = new BigInteger("8640000086400000000000"); - private static final BigInteger isoTimeLowerBound = isoTimeUpperBound.negate(); + /** nsMaxInstant + nsPerDay (exclusive) = 8.64 * 10**21 + 8.64 * 10**13. */ + private static final BigInt isoTimeUpperBound = upperEpochNSLimit.add(BI_NS_PER_DAY); + /** nsMinInstant - nsPerDay (exclusive) = -8.64 * 10**21 - 8.64 * 10**13. */ + private static final BigInt isoTimeLowerBound = isoTimeUpperBound.negate(); private static final int isoTimeBoundYears = 270000; - private static final int ISO_DATE_MAX_UTC_OFFSET_DAYS = 100_000_001; + private static final int ISO_DATE_MAX_UTC_OFFSET_DAYS = INSTANT_MAX_OFFSET_EPOCH_DAYS + 1; - // 8.64 * 10^13 - private static final BigInteger BI_8_64_13 = BigInteger.valueOf(86400000000000L); + /** maxTimeDuration = 2**53 * 10**9 - 1 = 9,007,199,254,740,991,999,999,999. */ + private static final BigInt MAX_TIME_DURATION = BigInt.valueOf(1L << 53).multiply(BigInt.valueOf(1_000_000_000L)).subtract(BigInt.ONE); public static final BigInteger BI_36_10_POW_11 = BigInteger.valueOf(3600000000000L); public static final BigInteger BI_6_10_POW_10 = BigInteger.valueOf(60000000000L); public static final BigInteger BI_10_POW_9 = BigInteger.valueOf(1000000000); // 10 ^ 9 public static final BigInteger BI_10_POW_6 = BigInteger.valueOf(1000000); // 10 ^ 6 - public static final BigInteger BI_2_POW_53 = BigInteger.valueOf(1L << 53); public static final BigInteger BI_1000 = BigInteger.valueOf(1000); // 10 ^ 3 public static final BigInteger BI_24 = BigInteger.valueOf(24); public static final BigInteger BI_60 = BigInteger.valueOf(60); @@ -309,9 +318,6 @@ public final class TemporalUtil { public static final int HOURS_PER_DAY = 24; public static final int MINUTES_PER_HOUR = 60; public static final int SECONDS_PER_MINUTE = 60; - public static final int MS_PER_DAY = 86_400_000; // 24 * 60 * 60 * 1000 - public static final double NS_PER_DAY = 8.64e13; // 24 * 60 * 60 * 1000 * 1000 * 1000 - public static final long NS_PER_DAY_LONG = (long) NS_PER_DAY; public static final int SINCE = -1; public static final int UNTIL = 1; @@ -381,6 +387,8 @@ public enum Unit { MICROSECOND(TemporalConstants.MICROSECOND), NANOSECOND(TemporalConstants.NANOSECOND); + @CompilationFinal(dimensions = 1) // + public static final Unit[] VALUES = values(); public static final Unit REQUIRED = null; private final TruffleString name; @@ -392,6 +400,40 @@ public enum Unit { public TruffleString toTruffleString() { return name; } + + public long getLengthInNanoseconds() { + return switch (this) { + case NANOSECOND -> 1; + case MICROSECOND -> 1_000L; + case MILLISECOND -> 1_000_000L; + case SECOND -> 1_000_000_000L; + case MINUTE -> 1_000_000_000L * SECONDS_PER_MINUTE; + case HOUR -> 1_000_000_000L * SECONDS_PER_MINUTE * MINUTES_PER_HOUR; + case DAY -> NS_PER_DAY_LONG; + default -> throw Errors.shouldNotReachHereUnexpectedValue(this); + }; + } + + public boolean isCalendarUnit() { + return switch (this) { + case YEAR, MONTH, WEEK -> true; + default -> false; + }; + } + + public boolean isDateUnit() { + return switch (this) { + case YEAR, MONTH, WEEK, DAY -> true; + default -> false; + }; + } + + public boolean isTimeUnit() { + return switch (this) { + case HOUR, MINUTE, SECOND, MILLISECOND, MICROSECOND, NANOSECOND -> true; + default -> false; + }; + } } public enum UnitPlural { @@ -732,11 +774,11 @@ public static UnsignedRoundingMode getUnsignedRoundingMode(RoundingMode rounding } public static double applyUnsignedRoundingMode(double x, double r1, double r2, UnsignedRoundingMode urm) { + assert urm != UnsignedRoundingMode.EMPTY; if (x == r1) { return r1; } assert r1 <= x && x <= r2; - assert urm != UnsignedRoundingMode.EMPTY; if (urm == UnsignedRoundingMode.ZERO) { return r1; } @@ -766,6 +808,40 @@ public static double applyUnsignedRoundingMode(double x, double r1, double r2, U return r2; } + @TruffleBoundary + public static double applyUnsignedRoundingMode(BigInt numerator, BigInt denominator, double r1, double r2, UnsignedRoundingMode urm) { + assert urm != UnsignedRoundingMode.EMPTY; + if (numerator.signum() == 0) { // x == r1 + return r1; + } + if (urm == UnsignedRoundingMode.ZERO) { + return r1; + } + if (urm == UnsignedRoundingMode.INFINITY) { + return r2; + } + // (|n|/|d| <=> 0.5) == (2*|n| <=> |d|) + int half = TemporalUtil.compareHalf(numerator, denominator); + if (half < 0) { + return r1; + } else if (half > 0) { + return r2; + } + // exactly half + if (urm == UnsignedRoundingMode.HALF_ZERO) { + return r1; + } + if (urm == UnsignedRoundingMode.HALF_INFINITY) { + return r2; + } + assert urm == UnsignedRoundingMode.HALF_EVEN; + double cardinality = (r1 / (r2 - r1)) % 2; + if (cardinality == 0) { + return r1; + } + return r2; + } + @TruffleBoundary public static double roundNumberToIncrement(double x, double increment, RoundingMode roundingMode) { assert JSRuntime.isIntegralNumber(increment) : increment; @@ -794,14 +870,10 @@ public static double roundNumberToIncrement(double x, double increment, Rounding } @TruffleBoundary - public static BigInteger roundNumberToIncrementAsIfPositive(BigDecimal x, BigDecimal increment, RoundingMode roundingMode) { - return roundNumberToIncrementAsIfPositiveAsBigDecimal(x, increment, roundingMode).toBigInteger(); - } - - private static BigDecimal roundNumberToIncrementAsIfPositiveAsBigDecimal(BigDecimal x, BigDecimal increment, RoundingMode roundingMode) { - BigDecimal[] divRes = x.divideAndRemainder(increment); - BigDecimal quotient = divRes[0]; - BigDecimal remainder = divRes[1]; + public static BigInt roundNumberToIncrementAsIfPositive(BigInt x, BigInt increment, RoundingMode roundingMode) { + BigInt[] divRes = x.divideAndRemainder(increment); + BigInt quotient = divRes[0]; + BigInt remainder = divRes[1]; int sign = remainder.signum(); if (sign == 0) { // already a multiple of increment, no rounding needed. @@ -809,11 +881,15 @@ private static BigDecimal roundNumberToIncrementAsIfPositiveAsBigDecimal(BigDeci } UnsignedRoundingMode unsignedRoundingMode = getUnsignedRoundingMode(roundingMode, false); - BigDecimal r1 = sign < 0 ? quotient.subtract(BigDecimal.ONE) : quotient; - BigDecimal r2 = sign >= 0 ? quotient.add(BigDecimal.ONE) : quotient; - int half = compareHalf(remainder, increment); + BigInt r1 = sign < 0 ? quotient.subtract(BigInt.ONE) : quotient; + BigInt r2 = sign >= 0 ? quotient.add(BigInt.ONE) : quotient; + BigInt rounded = applyUnsignedRoundingMode(remainder, increment, r1, r2, unsignedRoundingMode); + return rounded.multiply(increment); + } - BigDecimal rounded = switch (unsignedRoundingMode) { + private static BigInt applyUnsignedRoundingMode(BigInt remainder, BigInt increment, BigInt r1, BigInt r2, UnsignedRoundingMode unsignedRoundingMode) { + int half = compareHalf(remainder, increment); + return switch (unsignedRoundingMode) { // ("floor", "trunc") case ZERO -> r1; // ("ceil", "expand") @@ -834,20 +910,48 @@ private static BigDecimal roundNumberToIncrementAsIfPositiveAsBigDecimal(BigDeci } default -> throw Errors.shouldNotReachHereUnexpectedValue(unsignedRoundingMode); }; - - return rounded.multiply(increment); } /** * Returns the equivalent of comparing the decimal part of the quotient against 0.5, but * calculated from the division's remainder and divisor. */ - private static int compareHalf(BigDecimal remainder, BigDecimal divisor) { - return remainder.multiply(BigDecimal.valueOf(2)).abs().compareTo(divisor.abs()); + private static int compareHalf(BigInt remainder, BigInt divisor) { + return remainder.multiply(BigInt.valueOf(2)).abs().compareTo(divisor.abs()); + } + + private static boolean isEven(BigInt value) { + return !value.testBit(0); } - private static boolean isEven(BigDecimal value) { - return !value.toBigInteger().testBit(0); + @TruffleBoundary + public static BigInt roundNormalizedTimeDurationToIncrement(BigInt normalizedTimeDuration, long unitLengthInNs, int increment, RoundingMode roundingMode) { + BigInt normalizedIncrement = BigInt.valueOf(unitLengthInNs).multiply(BigInt.valueOf(increment)); + return roundNormalizedTimeDurationToIncrement(normalizedTimeDuration, normalizedIncrement, roundingMode); + } + + @TruffleBoundary + public static BigInt roundNormalizedTimeDurationToIncrement(BigInt normalizedTimeDuration, BigInt increment, RoundingMode roundingMode) { + BigInt[] divRes = normalizedTimeDuration.divideAndRemainder(increment); + BigInt quotient = divRes[0]; + BigInt remainder = divRes[1]; + int sign = remainder.signum(); + if (sign == 0) { + // already a multiple of increment, no rounding needed. + return normalizedTimeDuration; + } + boolean isNegative = sign < 0; + if (isNegative) { + quotient = quotient.negate(); + } + UnsignedRoundingMode unsignedRoundingMode = getUnsignedRoundingMode(roundingMode, isNegative); + BigInt r1 = quotient; + BigInt r2 = quotient.add(BigInt.ONE); + BigInt rounded = applyUnsignedRoundingMode(remainder, increment, r1, r2, unsignedRoundingMode); + if (isNegative) { + rounded = rounded.negate(); + } + return rounded.multiply(increment); } @TruffleBoundary @@ -1213,7 +1317,7 @@ public static boolean isoDateTimeWithinLimits(int year, int month, int day, int @TruffleBoundary private static boolean isoDateTimeWithinLimitsExact(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond, int nanosecond) { - BigInteger ns = getUTCEpochNanoseconds(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond); + BigInt ns = getUTCEpochNanoseconds(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond); return ns.compareTo(isoTimeLowerBound) > 0 && ns.compareTo(isoTimeUpperBound) < 0; } @@ -1232,7 +1336,8 @@ private static boolean isoDateTimeWithinLimitsExact(int year, int month, int day * @return number of nanoseconds since the epoch that corresponds to the given ISO 8601 calendar * date and wall-clock time in UTC. */ - public static BigInteger getUTCEpochNanoseconds(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond, int nanosecond) { + @TruffleBoundary + public static BigInt getUTCEpochNanoseconds(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond, int nanosecond) { assert isValidISODate(year, month, day) : List.of(year, month, day); assert isValidTime(hour, minute, second, millisecond, microsecond, nanosecond); @@ -1245,7 +1350,7 @@ public static BigInteger getUTCEpochNanoseconds(int year, int month, int day, in // Let epochNanoseconds be ms * 1e6 + microsecond * 1e3 + nanosecond. BigInteger epochNanoseconds = ms.multiply(BI_10_POW_6).add(BigInteger.valueOf(microsecond * 1000)).add(BigInteger.valueOf(nanosecond)); - return epochNanoseconds; + return BigInt.fromBigInteger(epochNanoseconds); } @TruffleBoundary @@ -1277,7 +1382,7 @@ public static Overflow toTemporalOverflow(JSDynamicObject options, TemporalGetOp private static Overflow toOverflow(TruffleString result) { if (CONSTRAIN.equals(result)) { return Overflow.CONSTRAIN; - } else if (TemporalConstants.REJECT.equals(result)) { + } else if (REJECT.equals(result)) { return Overflow.REJECT; } throw Errors.shouldNotReachHereUnexpectedValue(result); @@ -1398,12 +1503,12 @@ public static Number toIntegerOrInfinity(Object value) { } @TruffleBoundary - public static JSTemporalPlainDateObject calendarDateAdd(CalendarMethodsRecord calendarRec, JSDynamicObject date, JSDynamicObject duration) { + public static JSTemporalPlainDateObject calendarDateAdd(CalendarMethodsRecord calendarRec, JSTemporalPlainDateObject date, JSTemporalDurationObject duration) { return calendarDateAdd(calendarRec, date, duration, Undefined.instance); } @TruffleBoundary - public static JSTemporalPlainDateObject calendarDateAdd(CalendarMethodsRecord calendarRec, JSDynamicObject date, JSDynamicObject duration, JSDynamicObject options) { + public static JSTemporalPlainDateObject calendarDateAdd(CalendarMethodsRecord calendarRec, JSTemporalPlainDateObject date, JSTemporalDurationObject duration, JSDynamicObject options) { Object dateAddPrepared = calendarRec.dateAdd(); Object calendar = toCalendarObject(calendarRec.receiver()); Object addedDate = JSRuntime.call(dateAddPrepared, calendar, new Object[]{date, duration, options}); @@ -1418,6 +1523,11 @@ public static JSTemporalDurationObject calendarDateUntil(CalendarMethodsRecord c return requireTemporalDuration(date); } + private static JSTemporalDurationObject differenceDate(CalendarMethodsRecord calendarRec, JSDynamicObject one, JSDynamicObject two, JSDynamicObject untilOptions) { + // TODO + return calendarDateUntil(calendarRec, one, two, untilOptions); + } + public static Object toCalendarObject(Object calendarSlotValue) { Object calendar; if (calendarSlotValue instanceof TruffleString calendarID) { @@ -1430,25 +1540,25 @@ public static Object toCalendarObject(Object calendarSlotValue) { @TruffleBoundary public static BigInt roundTemporalInstant(BigInt ns, int increment, Unit unit, RoundingMode roundingMode) { - BigDecimal incrementNs = BigDecimal.valueOf(increment); + BigInt incrementNs = BigInt.valueOf(increment); if (Unit.HOUR == unit) { - incrementNs = incrementNs.multiply(BigDecimal.valueOf(3_600_000_000_000L)); + incrementNs = incrementNs.multiply(BigInt.valueOf(3_600_000_000_000L)); } else if (Unit.MINUTE == unit) { - incrementNs = incrementNs.multiply(BigDecimal.valueOf(60_000_000_000L)); + incrementNs = incrementNs.multiply(BigInt.valueOf(60_000_000_000L)); } else if (Unit.SECOND == unit) { - incrementNs = incrementNs.multiply(BigDecimal.valueOf(1_000_000_000L)); + incrementNs = incrementNs.multiply(BigInt.valueOf(1_000_000_000L)); } else if (Unit.MILLISECOND == unit) { - incrementNs = incrementNs.multiply(BigDecimal.valueOf(1_000_000L)); + incrementNs = incrementNs.multiply(BigInt.valueOf(1_000_000L)); } else if (Unit.MICROSECOND == unit) { - incrementNs = incrementNs.multiply(BigDecimal.valueOf(1_000L)); + incrementNs = incrementNs.multiply(BigInt.valueOf(1_000L)); } else { assert Unit.NANOSECOND == unit : unit; - if (incrementNs.compareTo(BigDecimal.ONE) == 0) { + if (incrementNs.compareTo(BigInt.ONE) == 0) { return ns; } } - var x = new BigDecimal(ns.bigIntegerValue()); - return BigInt.fromBigInteger(roundNumberToIncrementAsIfPositive(x, incrementNs, roundingMode)); + var x = ns; + return roundNumberToIncrementAsIfPositive(x, incrementNs, roundingMode); } public static ISODateRecord regulateISODate(int year, int monthParam, int dayParam, Overflow overflow) { @@ -1472,14 +1582,13 @@ public static ISODateRecord regulateISODate(int year, int monthParam, int dayPar */ @TruffleBoundary public static long isoDateToEpochDays(int year, int month, int date) { - // Year must be in the supported range for LocalDate. - assert year >= Year.MIN_VALUE && year <= Year.MAX_VALUE : year; int resolvedYear = year + month / 12; int resolvedMonth = month % 12; if (resolvedMonth < 0) { resolvedMonth += 12; } - + // Year must be in the supported range for LocalDate. + assert resolvedYear >= Year.MIN_VALUE && resolvedYear <= Year.MAX_VALUE : resolvedYear; long t = LocalDate.of(resolvedYear, resolvedMonth + 1, 1).atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli(); return Math.floorDiv(t, JSDate.MS_PER_DAY) + date - 1; } @@ -1494,12 +1603,25 @@ public static ISODateRecord balanceISODate(int year, int month, int day) { } long epochDays = isoDateToEpochDays(year, month - 1, day); long ms = epochDays * JSDate.MS_PER_DAY; - return new ISODateRecord(JSDate.yearFromTime(ms), JSDate.monthFromTime(ms) + 1, JSDate.dateFromTime(ms)); + return createISODateRecord(JSDate.yearFromTime(ms), JSDate.monthFromTime(ms) + 1, JSDate.dateFromTime(ms)); } @TruffleBoundary - public static ISODateRecord balanceISODate(double year, int month, double day) { - return balanceISODate((int) year, month, (int) day); + public static ISODateRecord createISODateRecord(int year, int month, int day) { + assert isValidISODate(year, month, day); + return new ISODateRecord(year, month, day); + } + + @TruffleBoundary + public static ISODateRecord balanceISODate(int year, int month, double day) { + assert JSRuntime.isIntegralNumber(day); + return balanceISODate(year, month, (int) day); + } + + @TruffleBoundary + public static ISODateRecord balanceISODate(double year, double month, double day) { + assert JSRuntime.isIntegralNumber(year) && JSRuntime.isIntegralNumber(month) && JSRuntime.isIntegralNumber(day); + return balanceISODate((int) year, (int) month, (int) day); } /** @@ -1514,8 +1636,7 @@ public static ISODateRecord addISODate(int year, int month, int day, int years, ISODateRecord intermediate = regulateISODate(intermediateYM.year(), intermediateYM.month(), day, overflow); days = days + 7 * weeks; int d = add(intermediate.day(), days, overflow); - intermediate = balanceISODate(intermediate.year(), intermediate.month(), d); - return regulateISODate(intermediate.year(), intermediate.month(), intermediate.day(), overflow); + return balanceISODate(intermediate.year(), intermediate.month(), d); } /** @@ -1735,36 +1856,61 @@ public static Unit largerOfTwoTemporalUnits(Unit a, Unit b) { } @TruffleBoundary - public static JSTemporalDurationRecord differenceISODateTime(JSContext ctx, JSRealm realm, EnumerableOwnPropertyNamesNode namesNode, int y1, int mon1, int d1, int h1, int min1, int s1, - int ms1, int mus1, int ns1, int y2, int mon2, int d2, int h2, int min2, int s2, int ms2, - int mus2, int ns2, CalendarMethodsRecord calendarRec, Unit largestUnit, JSDynamicObject options) { + public static NormalizedDurationRecord differenceISODateTime(JSContext ctx, JSRealm realm, EnumerableOwnPropertyNamesNode namesNode, + int y1, int mon1, int d1, int h1, int min1, int s1, int ms1, int mus1, int ns1, + int y2, int mon2, int d2, int h2, int min2, int s2, int ms2, int mus2, int ns2, + CalendarMethodsRecord calendarRec, Unit largestUnit, JSDynamicObject options) { assert options != null; - TimeDurationRecord timeDifference = differenceTime(h1, min1, s1, ms1, mus1, ns1, h2, min2, s2, ms2, mus2, ns2); - - int timeSign = durationSign(0, 0, 0, timeDifference.days(), timeDifference.hours(), timeDifference.minutes(), timeDifference.seconds(), - timeDifference.milliseconds(), timeDifference.microseconds(), timeDifference.nanoseconds()); + BigInt timeDuration = differenceTime(h1, min1, s1, ms1, mus1, ns1, h2, min2, s2, ms2, mus2, ns2); + int timeSign = normalizedTimeDurationSign(timeDuration); int dateSign = compareISODate(y2, mon2, d2, y1, mon1, d1); - ISODateRecord balanceResult = balanceISODate(y1, mon1, d1 + dtoi(timeDifference.days())); + + ISODateRecord adjustedDate = createISODateRecord(y1, mon1, d1); if (timeSign == -dateSign) { - balanceResult = balanceISODate(balanceResult.year(), balanceResult.month(), balanceResult.day() - timeSign); - timeDifference = balanceTimeDuration(-timeSign, timeDifference.hours(), - timeDifference.minutes(), timeDifference.seconds(), timeDifference.milliseconds(), timeDifference.microseconds(), timeDifference.nanoseconds(), largestUnit); + adjustedDate = balanceISODate(adjustedDate.year(), adjustedDate.month(), adjustedDate.day() - timeSign); + timeDuration = add24HourDaysToNormalizedTimeDuration(timeDuration, -timeSign); } - JSDynamicObject date1 = JSTemporalPlainDate.create(ctx, realm, balanceResult.year(), balanceResult.month(), balanceResult.day(), calendarRec.receiver(), null, + + JSDynamicObject date1 = JSTemporalPlainDate.create(ctx, realm, adjustedDate.year(), adjustedDate.month(), adjustedDate.day(), calendarRec.receiver(), null, InlinedBranchProfile.getUncached()); JSDynamicObject date2 = JSTemporalPlainDate.create(ctx, realm, y2, mon2, d2, calendarRec.receiver(), null, InlinedBranchProfile.getUncached()); + Unit dateLargestUnit = largerOfTwoTemporalUnits(Unit.DAY, largestUnit); - JSDynamicObject untilOptions = mergeLargestUnitOption(ctx, namesNode, options, dateLargestUnit); - JSTemporalDurationObject dateDifference = calendarDateUntil(calendarRec, date1, date2, untilOptions); - TimeDurationRecord result = balanceTimeDuration(dateDifference.getDays(), timeDifference.hours(), timeDifference.minutes(), timeDifference.seconds(), - timeDifference.milliseconds(), timeDifference.microseconds(), timeDifference.nanoseconds(), largestUnit); - return JSTemporalDurationRecord.createWeeks(dateDifference.getYears(), dateDifference.getMonths(), dateDifference.getWeeks(), result.days(), result.hours(), result.minutes(), - result.seconds(), result.milliseconds(), result.microseconds(), result.nanoseconds()); + JSObject untilOptions = mergeLargestUnitOption(ctx, namesNode, options, dateLargestUnit); + + JSTemporalDurationObject dateDifference = differenceDate(calendarRec, date1, date2, untilOptions); + double days = dateDifference.getDays(); + if (largestUnit != dateLargestUnit) { + timeDuration = add24HourDaysToNormalizedTimeDuration(timeDuration, days); + days = 0; + } + return createNormalizedDurationRecord(dateDifference.getYears(), dateDifference.getMonths(), dateDifference.getWeeks(), days, timeDuration); + } + + public static DateDurationRecord createDateDurationRecord(double years, double months, double weeks, double days) { + if (!isValidDuration(years, months, weeks, days, 0, 0, 0, 0, 0, 0)) { + throw TemporalErrors.createTypeErrorDurationOutsideRange(); + } + return new DateDurationRecord(years, months, weeks, days); + } + + public static NormalizedDurationRecord createNormalizedDurationRecord(double years, double months, double weeks, double days, BigInt normalizedTimeDuration) { + DateDurationRecord dateDurationRecord = createDateDurationRecord(years, months, weeks, days); + return combineDateAndNormalizedTimeDuration(dateDurationRecord, normalizedTimeDuration); + } + + public static NormalizedDurationRecord combineDateAndNormalizedTimeDuration(DateDurationRecord dateDuration, BigInt normalizedTimeDuration) { + int dateSign = durationSign(dateDuration.years(), dateDuration.months(), dateDuration.weeks(), dateDuration.days(), 0, 0, 0, 0, 0, 0); + int timeSign = normalizedTimeDurationSign(normalizedTimeDuration); + if (dateSign != 0 && timeSign != 0 && dateSign != timeSign) { + throw Errors.createRangeError("mixed-sign values not allowed as duration fields"); + } + return new NormalizedDurationRecord(dateDuration.years(), dateDuration.months(), dateDuration.weeks(), dateDuration.days(), normalizedTimeDuration); } @TruffleBoundary - public static JSDynamicObject mergeLargestUnitOption(JSContext ctx, EnumerableOwnPropertyNamesNode namesNode, JSDynamicObject options, Unit largestUnit) { - JSDynamicObject merged = JSOrdinary.createWithNullPrototype(ctx); + public static JSObject mergeLargestUnitOption(JSContext ctx, EnumerableOwnPropertyNamesNode namesNode, JSDynamicObject options, Unit largestUnit) { + JSObject merged = JSOrdinary.createWithNullPrototype(ctx); UnmodifiableArrayList keys = namesNode.execute(options); for (Object nextKey : keys) { if (nextKey instanceof TruffleString key) { @@ -1909,10 +2055,6 @@ public static void rejectDurationSign(double years, double months, double weeks, } } - public static TimeDurationRecord balanceTimeDuration(TimeDurationRecord norm, Unit largestUnit) { - return balanceTimeDuration(norm.days(), norm.hours(), norm.minutes(), norm.seconds(), norm.milliseconds(), norm.microseconds(), norm.nanoseconds(), largestUnit); - } - public static TimeDurationRecord balanceTimeDuration(BigInt nanoseconds, Unit largestUnit) { TimeDurationRecord result = balancePossiblyInfiniteTimeDuration(nanoseconds, largestUnit); if (result.isOverflow()) { @@ -1921,21 +2063,6 @@ public static TimeDurationRecord balanceTimeDuration(BigInt nanoseconds, Unit la return result; } - public static TimeDurationRecord balanceTimeDuration(double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds, Unit largestUnit) { - TimeDurationRecord result = balancePossiblyInfiniteTimeDuration(days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, largestUnit); - if (result.isOverflow()) { - throw Errors.createRangeError("Time is infinite"); - } - return result; - } - - @TruffleBoundary - public static TimeDurationRecord balancePossiblyInfiniteTimeDuration(double days, double hours, double minutes, double seconds, - double milliseconds, double microseconds, double nanoseconds, Unit largestUnit) { - BigInt ns = totalDurationNanoseconds(days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds); - return balancePossiblyInfiniteTimeDuration(ns, largestUnit); - } - @TruffleBoundary private static TimeDurationRecord balancePossiblyInfiniteTimeDuration(BigInt nanoseconds, Unit largestUnit) { BigInteger ns = nanoseconds.bigIntegerValue(); @@ -2032,68 +2159,6 @@ private static TimeDurationRecord balancePossiblyInfiniteTimeDuration(BigInt nan ms.doubleValue() * sign, us.doubleValue() * sign, ns.doubleValue() * sign); } - public static TimeDurationRecord balanceTimeDurationRelative(double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds, - Unit largestUnit, JSTemporalZonedDateTimeObject zonedRelativeTo, TimeZoneMethodsRecord timeZoneRec, JSTemporalPlainDateTimeObject precalculatedPlainDateTimeOpt, - JSContext context, JSRealm realm) { - TimeDurationRecord result = balancePossiblyInfiniteTimeDurationRelative(days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, largestUnit, - zonedRelativeTo, timeZoneRec, precalculatedPlainDateTimeOpt, context, realm); - double overflow = result.getOverflow(); - if (Double.isInfinite(overflow)) { - throw Errors.createRangeError("Time is infinite"); - } - return result; - } - - @TruffleBoundary - public static TimeDurationRecord balancePossiblyInfiniteTimeDurationRelative(double days, double hours, double minutes, double seconds, - double milliseconds, double microseconds, double nanoseconds, Unit largestUnit, - JSTemporalZonedDateTimeObject zonedRelativeTo, TimeZoneMethodsRecord timeZoneRec, JSTemporalPlainDateTimeObject precalculatedPlainDateTimeOpt, - JSContext context, JSRealm realm) { - JSTemporalPlainDateTimeObject precalculatedPlainDateTime = precalculatedPlainDateTimeOpt; - BigInt intermediateNs = zonedRelativeTo.getNanoseconds(); - JSTemporalInstantObject startInstant = JSTemporalInstant.create(context, realm, intermediateNs); - if (days != 0) { - if (precalculatedPlainDateTime == null) { - JSTemporalCalendarObject iso8601Calendar = getISO8601Calendar(context, realm); - precalculatedPlainDateTime = builtinTimeZoneGetPlainDateTimeFor(context, realm, timeZoneRec, startInstant, iso8601Calendar); - } - var intermediateResult = addDaysToZonedDateTime(context, realm, startInstant, precalculatedPlainDateTime, timeZoneRec, dtoi(days)); - intermediateNs = intermediateResult.epochNanoseconds(); - } - BigInt endNs = addInstant(intermediateNs, hours, minutes, seconds, milliseconds, microseconds, nanoseconds); - BigInt nanosecondsToBalance = endNs.subtract(zonedRelativeTo.getNanoseconds()); - if (nanosecondsToBalance.compareTo(BigInt.ZERO) == 0) { - return new TimeDurationRecord(0, 0, 0, 0, 0, 0, 0); - } - double balancedDays; - Unit largestTimeUnit = largestUnit; - switch (largestUnit) { - case YEAR, MONTH, WEEK, DAY -> { - if (precalculatedPlainDateTime == null) { - JSTemporalCalendarObject iso8601Calendar = getISO8601Calendar(context, realm); - precalculatedPlainDateTime = builtinTimeZoneGetPlainDateTimeFor(context, realm, timeZoneRec, startInstant, iso8601Calendar); - } - var result = normalizedTimeDurationToDays(context, realm, nanosecondsToBalance, zonedRelativeTo, timeZoneRec, precalculatedPlainDateTime); - balancedDays = result.days().doubleValue(); - if (Double.isInfinite(balancedDays)) { - // If days is not finite, return positive/negative overflow. - return new TimeDurationRecord(balancedDays, 0, 0, 0, 0, 0, 0); - } - nanosecondsToBalance = BigInt.fromBigInteger(result.remainder()); - largestTimeUnit = Unit.HOUR; - } - default -> { - balancedDays = 0; - } - } - var balanceResult = balancePossiblyInfiniteTimeDuration(nanosecondsToBalance, largestTimeUnit); - if (balanceResult.isOverflow()) { - return balanceResult; - } - return new TimeDurationRecord(balancedDays, balanceResult.hours(), balanceResult.minutes(), balanceResult.seconds(), - balanceResult.milliseconds(), balanceResult.microseconds(), balanceResult.nanoseconds()); - } - public static JSDynamicObject toDynamicObject(Object obj) { if (obj instanceof JSDynamicObject) { return (JSDynamicObject) obj; @@ -2112,38 +2177,6 @@ public static JSDynamicObject toJSDynamicObject(Object item, Node node, InlinedB } } - public static JSTemporalDurationRecord differenceZonedDateTime(JSContext ctx, JSRealm realm, EnumerableOwnPropertyNamesNode namesNode, - BigInt ns1, BigInt ns2, TimeZoneMethodsRecord timeZone, CalendarMethodsRecord calendar, Unit largestUnit, - JSTemporalPlainDateTimeObject precalculatedPlainDateTime) { - return differenceZonedDateTime(ctx, realm, namesNode, ns1, ns2, timeZone, calendar, largestUnit, precalculatedPlainDateTime, Undefined.instance); - } - - public static JSTemporalDurationRecord differenceZonedDateTime(JSContext ctx, JSRealm realm, EnumerableOwnPropertyNamesNode namesNode, - BigInt ns1, BigInt ns2, TimeZoneMethodsRecord timeZoneRec, CalendarMethodsRecord calendarRec, Unit largestUnit, - JSTemporalPlainDateTimeObject precalculatedPlainDateTime, JSDynamicObject options) { - if (ns1.equals(ns2)) { - return JSTemporalDurationRecord.createWeeks(0, 0, 0, 0, 0, 0, 0, 0, 0, 0); - } - JSTemporalInstantObject startInstant = JSTemporalInstant.create(ctx, realm, ns1); - JSTemporalPlainDateTimeObject startDateTime = builtinTimeZoneGetPlainDateTimeFor(ctx, realm, timeZoneRec, startInstant, calendarRec.receiver()); - JSTemporalInstantObject endInstant = JSTemporalInstant.create(ctx, realm, ns2); - JSTemporalPlainDateTimeObject endDateTime = builtinTimeZoneGetPlainDateTimeFor(ctx, realm, timeZoneRec, endInstant, calendarRec.receiver()); - JSTemporalDurationRecord dateDifference = differenceISODateTime(ctx, realm, namesNode, startDateTime.getYear(), startDateTime.getMonth(), startDateTime.getDay(), startDateTime.getHour(), - startDateTime.getMinute(), startDateTime.getSecond(), startDateTime.getMillisecond(), startDateTime.getMicrosecond(), startDateTime.getNanosecond(), - endDateTime.getYear(), endDateTime.getMonth(), endDateTime.getDay(), endDateTime.getHour(), endDateTime.getMinute(), endDateTime.getSecond(), - endDateTime.getMillisecond(), endDateTime.getMicrosecond(), endDateTime.getNanosecond(), calendarRec, largestUnit, options); - BigInt intermediateNs = addZonedDateTime(ctx, realm, ns1, timeZoneRec, calendarRec, dtol(dateDifference.getYears()), dtol(dateDifference.getMonths()), dtol(dateDifference.getWeeks()), 0, 0, 0, - 0, 0, - 0, 0, precalculatedPlainDateTime); - BigInt timeRemainderNs = ns2.subtract(intermediateNs); - JSTemporalZonedDateTimeObject intermediate = JSTemporalZonedDateTime.create(ctx, realm, intermediateNs, timeZoneRec.receiver(), calendarRec.receiver()); - NormalizedTimeDurationToDaysResult result = normalizedTimeDurationToDays(ctx, realm, timeRemainderNs, intermediate, timeZoneRec); - TimeDurationRecord timeDifference = balanceTimeDuration(BigInt.fromBigInteger(result.remainder()), Unit.HOUR); - - return JSTemporalDurationRecord.createWeeks(dateDifference.getYears(), dateDifference.getMonths(), dateDifference.getWeeks(), bitod(result.days()), timeDifference.hours(), - timeDifference.minutes(), timeDifference.seconds(), timeDifference.milliseconds(), timeDifference.microseconds(), timeDifference.nanoseconds()); - } - public static boolean isValidDuration(double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds) { int sign = durationSign(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, @@ -2262,79 +2295,6 @@ public static double roundDurationCalculateFractionalSeconds(double seconds, dou return part1.add(part2).add(part3).add(BigDecimal.valueOf(seconds)).doubleValue(); } - public static NormalizedTimeDurationToDaysResult normalizedTimeDurationToDays(JSContext ctx, JSRealm realm, BigInt nanoseconds, JSTemporalZonedDateTimeObject zonedRelativeTo, - TimeZoneMethodsRecord timeZoneRec) { - return normalizedTimeDurationToDays(ctx, realm, nanoseconds, zonedRelativeTo, timeZoneRec, null); - } - - @TruffleBoundary - public static NormalizedTimeDurationToDaysResult normalizedTimeDurationToDays(JSContext ctx, JSRealm realm, BigInt norm, JSTemporalZonedDateTimeObject zonedRelativeTo, - TimeZoneMethodsRecord timeZoneRec, JSTemporalPlainDateTimeObject precalculatedPlainDateTimeOpt) { - BigInteger nanoseconds = norm.bigIntegerValue(); - int sign = nanoseconds.signum(); - BigInteger signBI = BigInteger.valueOf(sign); - BigInteger dayLengthNs = BI_8_64_13; - if (sign == 0) { - return new NormalizedTimeDurationToDaysResult(BigInteger.ZERO, BigInteger.ZERO, dayLengthNs); - } - BigInt startNs = zonedRelativeTo.getNanoseconds(); - JSTemporalInstantObject startInstant = JSTemporalInstant.create(ctx, realm, startNs); - BigInt endNs = startNs.add(norm); - JSTemporalPlainDateTimeObject startDateTime = precalculatedPlainDateTimeOpt != null ? precalculatedPlainDateTimeOpt - : builtinTimeZoneGetPlainDateTimeFor(ctx, realm, timeZoneRec, startInstant, TemporalConstants.ISO8601); - JSTemporalInstantObject endInstant = JSTemporalInstant.create(ctx, realm, endNs); - JSTemporalPlainDateTimeObject endDateTime = builtinTimeZoneGetPlainDateTimeFor(ctx, realm, timeZoneRec, endInstant, TemporalConstants.ISO8601); - var date1 = JSTemporalPlainDate.create(ctx, realm, startDateTime.getYear(), startDateTime.getMonth(), startDateTime.getDay(), TemporalConstants.ISO8601, null, - InlinedBranchProfile.getUncached()); - var date2 = JSTemporalPlainDate.create(ctx, realm, endDateTime.getYear(), endDateTime.getMonth(), endDateTime.getDay(), TemporalConstants.ISO8601, null, InlinedBranchProfile.getUncached()); - int days = (int) daysUntil(date1, date2); - int timeSign = compareTemporalTime(startDateTime.getHour(), startDateTime.getMinute(), startDateTime.getSecond(), startDateTime.getMillisecond(), startDateTime.getMicrosecond(), - startDateTime.getNanosecond(), - endDateTime.getHour(), endDateTime.getMinute(), endDateTime.getSecond(), endDateTime.getMillisecond(), endDateTime.getMicrosecond(), endDateTime.getNanosecond()); - if (days > 0 && timeSign > 0) { - days--; - } else if (days < 0 && timeSign < 0) { - days++; - } - AddDaysToZonedDateTimeResult relativeResult = addDaysToZonedDateTime(ctx, realm, startInstant, startDateTime, timeZoneRec, days); - if (sign == 1 && days > 0 && relativeResult.epochNanoseconds().compareTo(endNs) > 0) { - days = days - 1; - relativeResult = addDaysToZonedDateTime(ctx, realm, startInstant, startDateTime, timeZoneRec, days); - if (days > 0 && relativeResult.epochNanoseconds().compareTo(endNs) > 0) { - throw Errors.createRangeError("Invalid result of AddDaysToZonedDateTime()"); - } - } - nanoseconds = endNs.subtract(relativeResult.epochNanoseconds()).bigIntegerValue(); - AddDaysToZonedDateTimeResult oneDayFarther = addDaysToZonedDateTime(ctx, realm, relativeResult.instant(), relativeResult.dateTime(), timeZoneRec, sign); - dayLengthNs = oneDayFarther.epochNanoseconds().subtract(relativeResult.epochNanoseconds()).bigIntegerValue(); - BigInteger oneDayLess = nanoseconds.subtract(dayLengthNs); - if (oneDayLess.multiply(signBI).signum() >= 0) { - nanoseconds = oneDayLess; - relativeResult = oneDayFarther; - days = days + sign; - oneDayFarther = addDaysToZonedDateTime(ctx, realm, relativeResult.instant(), relativeResult.dateTime(), timeZoneRec, sign); - dayLengthNs = oneDayFarther.epochNanoseconds().subtract(relativeResult.epochNanoseconds()).bigIntegerValue(); - if (nanoseconds.subtract(dayLengthNs).multiply(signBI).signum() >= 0) { - throw Errors.createRangeError("Invalid result of AddDaysToZonedDateTime()"); - } - } - if ((days < 0 && sign == 1) || (days > 0 && sign == -1)) { - throw Errors.createRangeError("NanosecondsToDays returned invalid days"); - } - if (sign == -1) { - if (nanoseconds.signum() == 1) { - throw Errors.createRangeError("NanosecondsToDays returned invalid nanoseconds"); - } - } else { - assert nanoseconds.signum() >= 0; - } - assert nanoseconds.abs().compareTo(dayLengthNs.abs()) < 0; - if (dayLengthNs.compareTo(BI_2_POW_53) >= 0) { - throw Errors.createRangeError("Day length out of range"); - } - return new NormalizedTimeDurationToDaysResult(BigInteger.valueOf(days), nanoseconds, dayLengthNs.abs()); - } - public record AddDaysToZonedDateTimeResult(BigInt epochNanoseconds, JSTemporalInstantObject instant, JSTemporalPlainDateTimeObject dateTime) { } @@ -2360,41 +2320,8 @@ public static AddDaysToZonedDateTimeResult addDaysToZonedDateTime(JSContext ctx, return new AddDaysToZonedDateTimeResult(instantResult.getNanoseconds(), instant, dateTimeResult); } - // TODO doing some long arithmetics here. Might need double/BigInteger - public static JSTemporalDurationRecord adjustRoundedDurationDays(JSContext ctx, JSRealm realm, - TemporalDurationAddNode durationAddNode, TemporalRoundDurationNode roundDurationNode, double years, - double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds, int increment, - Unit unit, RoundingMode roundingMode, JSTemporalZonedDateTimeObject zonedRelativeTo, - CalendarMethodsRecord calendarRec, TimeZoneMethodsRecord timeZoneRec, JSTemporalPlainDateTimeObject precalculatedPlainDateTime) { - if (zonedRelativeTo == null || - unit == Unit.YEAR || unit == Unit.MONTH || unit == Unit.WEEK || unit == Unit.DAY || - (unit == Unit.NANOSECOND && increment == 1)) { - return JSTemporalDurationRecord.createWeeks(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds); - } - long timeRemainderNs = totalDurationNanoseconds(0, hours, minutes, seconds, milliseconds, microseconds, nanoseconds).longValue(); - int direction = Long.signum(timeRemainderNs); - BigInt dayStart = addZonedDateTime(ctx, realm, - zonedRelativeTo.getNanoseconds(), timeZoneRec, calendarRec, - dtol(years), dtol(months), dtol(weeks), dtol(days), 0, 0, 0, 0, 0, 0, precalculatedPlainDateTime); - JSTemporalInstantObject dayStartInstant = JSTemporalInstant.create(ctx, realm, dayStart); - JSTemporalPlainDateTimeObject dayStartDateTime = builtinTimeZoneGetPlainDateTimeFor(ctx, realm, timeZoneRec, dayStartInstant, calendarRec.receiver()); - var dayEnd = addDaysToZonedDateTime(ctx, realm, dayStartInstant, dayStartDateTime, timeZoneRec, direction); - long dayLengthNs = bigIntToLong(dayEnd.epochNanoseconds().subtract(dayStart)); - long oneDayLess = timeRemainderNs - dayLengthNs; - if ((oneDayLess * direction) < 0) { - return JSTemporalDurationRecord.createWeeks(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds); - } - JSTemporalDurationRecord add = durationAddNode.execute(dtol(years), dtol(months), dtol(weeks), dtol(days), 0, 0, 0, 0, - 0, 0, 0, 0, 0, direction, 0, 0, 0, 0, 0, 0, - zonedRelativeTo, calendarRec, timeZoneRec, precalculatedPlainDateTime); - JSTemporalDurationRecord atd = roundDurationNode.execute(0, 0, 0, 0, 0, 0, 0, 0, 0, oneDayLess, increment, unit, roundingMode); - var btd = balanceTimeDuration(0, atd.getHours(), atd.getMinutes(), atd.getSeconds(), - atd.getMilliseconds(), atd.getMicroseconds(), atd.getNanoseconds(), Unit.HOUR); - return JSTemporalDurationRecord.createWeeks(add.getYears(), add.getMonths(), add.getWeeks(), add.getDays(), - btd.hours(), btd.minutes(), btd.seconds(), btd.milliseconds(), btd.microseconds(), btd.nanoseconds()); - } - private static BigInteger dtobi(double d) { + CompilerAsserts.neverPartOfCompilation(); return new BigDecimal(d).toBigInteger(); } @@ -2411,16 +2338,116 @@ public static BigInt totalDurationNanoseconds(double days, double hours, double return BigInt.fromBigInteger(ns); } + /** + * {@return normalized time duration consisting of whole seconds, and subseconds expressed in + * nanoseconds}. + * + * The normalized time duration can be stored losslessly in two 64-bit floating point numbers. + * Alternatively, normalizedSeconds * 10**9 + subseconds can be stored as a 96-bit integer. + */ + @TruffleBoundary + public static BigInt normalizeTimeDuration(double hours, double minutes, double seconds, + double milliseconds, double microseconds, double nanoseconds) { + BigInteger h = dtobi(hours); + BigInteger min = dtobi(minutes).add(h.multiply(BI_60)); + BigInteger s = dtobi(seconds).add(min.multiply(BI_60)); + BigInteger ms = dtobi(milliseconds).add(s.multiply(BI_1000)); + BigInteger us = dtobi(microseconds).add(ms.multiply(BI_1000)); + BigInteger ns = dtobi(nanoseconds).add(us.multiply(BI_1000)); + return BigInt.fromBigInteger(ns); + } + + @TruffleBoundary + public static BigInt add24HourDaysToNormalizedTimeDuration(BigInt timeDurationTotalNanoseconds, double days) { + assert JSRuntime.isIntegralNumber(days) : days; + BigInt result = timeDurationTotalNanoseconds.add(BigInt.fromBigInteger(dtobi(days)).multiply(BI_NS_PER_DAY)); + if (result.abs().compareTo(MAX_TIME_DURATION) > 0) { + throw Errors.createRangeError("Time duration out of range"); + } + return result; + } + + @TruffleBoundary + public static BigInt addNormalizedTimeDurationToEpochNanoseconds(BigInt timeDurationTotalNanoseconds, BigInt epochNs) { + return epochNs.add(timeDurationTotalNanoseconds); + } + + @TruffleBoundary + public static BigInt addNormalizedTimeDuration(BigInt one, BigInt two) { + BigInt result = one.add(two); + if (result.abs().compareTo(MAX_TIME_DURATION) > 0) { + throw Errors.createRangeError("Time duration out of range"); + } + return result; + } + + @TruffleBoundary + public static BigInt subtractNormalizedTimeDuration(BigInt one, BigInt two) { + BigInt result = one.subtract(two); + if (result.abs().compareTo(MAX_TIME_DURATION) > 0) { + throw Errors.createRangeError("Time duration out of range"); + } + return result; + } + + @TruffleBoundary + public static BigInt normalizedTimeDurationFromEpochNanosecondsDifference(BigInt one, BigInt two) { + BigInt result = one.subtract(two); + assert result.abs().compareTo(MAX_TIME_DURATION) <= 0 : result; + return result; + } + + @TruffleBoundary + public static double divideNormalizedTimeDurationAsDouble(BigInt normalizedTimeDuration, long divisor) { + assert divisor != 0; + BigDecimal result = new BigDecimal(normalizedTimeDuration.bigIntegerValue()).divide(BigDecimal.valueOf(divisor), MathContext.DECIMAL128); + return result.doubleValue(); + } + + @TruffleBoundary + public static double divideNormalizedTimeDurationAsDoubleTruncate(BigInt normalizedTimeDuration, long divisor) { + assert divisor != 0; + return normalizedTimeDuration.divide(BigInt.valueOf(divisor)).doubleValue(); + } + + @TruffleBoundary + public static BigInt remainderNormalizedTimeDuration(BigInt normalizedTimeDuration, long divisor) { + assert divisor != 0; + BigDecimal result = new BigDecimal(normalizedTimeDuration.bigIntegerValue()).remainder(BigDecimal.valueOf(divisor), MathContext.DECIMAL128); + return BigInt.fromBigInteger(result.toBigInteger()); + } + + @TruffleBoundary + public static double normalizeTimeDurationSeconds(BigInt timeDurationTotalNanoseconds) { + return timeDurationTotalNanoseconds.bigIntegerValue().divide(BI_10_POW_9).doubleValue(); + } + + @TruffleBoundary + public static double normalizeTimeDurationSubseconds(BigInt timeDurationTotalNanoseconds) { + return timeDurationTotalNanoseconds.bigIntegerValue().remainder(BI_10_POW_9).doubleValue(); + } + + public static BigInt normalizedTimeDurationAbs(BigInt timeDurationTotalNanoseconds) { + return timeDurationTotalNanoseconds.abs(); + } + + public static int normalizedTimeDurationSign(BigInt timeDurationTotalNanoseconds) { + return timeDurationTotalNanoseconds.signum(); + } + + public static BigInt zeroTimeDuration() { + return BigInt.ZERO; + } + @TruffleBoundary public static long daysUntil(JSTemporalPlainDateObject earlier, JSTemporalPlainDateObject later) { - double epochDays1 = JSDate.makeDay(earlier.getYear(), earlier.getMonth() - 1, earlier.getDay()); - assert Double.isFinite(epochDays1); - double epochDays2 = JSDate.makeDay(later.getYear(), later.getMonth() - 1, later.getDay()); - assert Double.isFinite(epochDays2); - return dtol(epochDays2 - epochDays1); + long epochDays1 = isoDateToEpochDays(earlier.getYear(), earlier.getMonth() - 1, earlier.getDay()); + long epochDays2 = isoDateToEpochDays(later.getYear(), later.getMonth() - 1, later.getDay()); + return epochDays2 - epochDays1; } - public static TimeDurationRecord differenceTime(int h1, int min1, int s1, int ms1, int mus1, int ns1, + public static BigInt differenceTime( + int h1, int min1, int s1, int ms1, int mus1, int ns1, int h2, int min2, int s2, int ms2, int mus2, int ns2) { int hours = h2 - h1; int minutes = min2 - min1; @@ -2428,10 +2455,33 @@ public static TimeDurationRecord differenceTime(int h1, int min1, int s1, int ms int milliseconds = ms2 - ms1; int microseconds = mus2 - mus1; int nanoseconds = ns2 - ns1; - int sign = durationSign(0, 0, 0, 0, hours, minutes, seconds, milliseconds, microseconds, nanoseconds); - TimeRecord bt = balanceTime(hours * sign, minutes * sign, seconds * sign, milliseconds * sign, microseconds * sign, nanoseconds * sign); - return new TimeDurationRecord(bt.days() * sign, bt.hour() * sign, bt.minute() * sign, bt.second() * sign, - bt.millisecond() * sign, bt.microsecond() * sign, bt.nanosecond() * sign); + BigInt norm = normalizeTimeDuration(hours, minutes, seconds, milliseconds, microseconds, nanoseconds); + assert normalizedTimeDurationAbs(norm).compareTo(BI_NS_PER_DAY) < 0 : norm; + return norm; + } + + /** + * RoundTimeDuration result. + */ + public record NormalizedDurationWithTotalRecord(NormalizedDurationRecord normalizedDuration, double total) { + } + + public static NormalizedDurationWithTotalRecord roundTimeDuration(double days0, BigInt norm0, int increment, Unit unit, RoundingMode roundingMode) { + assert !unit.isCalendarUnit() : unit; + double days = days0; + BigInt norm = norm0; + double total; + if (unit == Unit.DAY) { + double fractionalDays = days + divideNormalizedTimeDurationAsDouble(norm, NS_PER_DAY_LONG); + days = roundNumberToIncrement(fractionalDays, increment, roundingMode); + total = fractionalDays; + norm = zeroTimeDuration(); + } else { + long divisor = unit.getLengthInNanoseconds(); + total = divideNormalizedTimeDurationAsDouble(norm, divisor); + norm = roundNormalizedTimeDurationToIncrement(norm, divisor, increment, roundingMode); + } + return new NormalizedDurationWithTotalRecord(createNormalizedDurationRecord(0, 0, 0, days, norm), total); } @TruffleBoundary @@ -2586,6 +2636,16 @@ public static TimeRecord addTimeDouble(int hour, int minute, int second, int mil microsecond + microseconds, nanosecond + nanoseconds, node, errorBranch); } + @TruffleBoundary + public static TimeRecord addTime(int hour, int minute, int second, int millisecond, int microsecond, double nanosecond, + BigInt normalizedTimeDuration, + Node node, InlinedBranchProfile errorBranch) { + BigInteger[] qr = normalizedTimeDuration.bigIntegerValue().divideAndRemainder(BI_10_POW_9); + double seconds = second + qr[0].doubleValue(); // NormalizedTimeDurationSeconds + double nanoseconds = nanosecond + qr[1].doubleValue(); // NormalizedTimeDurationSubseconds + return balanceTimeDouble(hour, minute, seconds, millisecond, microsecond, nanoseconds, node, errorBranch); + } + @TruffleBoundary public static JSTemporalDurationRecord roundISODateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond, int nanosecond, int increment, Unit unit, RoundingMode roundingMode, Long dayLength) { @@ -2790,19 +2850,25 @@ public static BigInt addInstant(BigInt epochNanoseconds, long hours, long minute } @TruffleBoundary - public static TimeDurationRecord differenceInstant(BigInt ns1, BigInt ns2, int roundingIncrement, Unit smallestUnit, Unit largestUnit, RoundingMode roundingMode, - TemporalRoundDurationNode roundDuration) { - BigInteger difference = ns2.subtract(ns1).bigIntegerValue(); - int nanoseconds = difference.remainder(BI_1000).intValue(); - int microseconds = difference.divide(BI_1000).remainder(BI_1000).intValue(); - int milliseconds = difference.divide(BI_10_POW_6).remainder(BI_1000).intValue(); - long seconds = difference.divide(BI_10_POW_9).longValue(); - if (smallestUnit == Unit.NANOSECOND && roundingIncrement == 1) { - return balanceTimeDuration(0, 0, 0, seconds, milliseconds, microseconds, nanoseconds, largestUnit); + public static BigInt addInstant(BigInt epochNanoseconds, BigInt normalizedTimeDuration) { + BigInt result = addNormalizedTimeDurationToEpochNanoseconds(normalizedTimeDuration, epochNanoseconds); + if (!isValidEpochNanoseconds(result)) { + throw TemporalErrors.createRangeErrorInvalidNanoseconds(); } - var roundResult = roundDuration.execute(0, 0, 0, 0, 0, 0, seconds, milliseconds, microseconds, nanoseconds, roundingIncrement, smallestUnit, roundingMode); - return balanceTimeDuration(0, roundResult.getHours(), roundResult.getMinutes(), roundResult.getSeconds(), - roundResult.getMilliseconds(), roundResult.getMicroseconds(), roundResult.getNanoseconds(), largestUnit); + return result; // spec return type: BigInt + } + + /** + * DifferenceInstant result. + */ + public record NormalizedTimeDurationWithTotalRecord(BigInt normalizedTimeDuration, double total) { + } + + @TruffleBoundary + public static NormalizedTimeDurationWithTotalRecord differenceInstant(BigInt ns1, BigInt ns2, int roundingIncrement, Unit smallestUnit, RoundingMode roundingMode) { + BigInt difference = normalizedTimeDurationFromEpochNanosecondsDifference(ns2, ns1); + var roundRecord = roundTimeDuration(0, difference, roundingIncrement, smallestUnit, roundingMode); + return new NormalizedTimeDurationWithTotalRecord(roundRecord.normalizedDuration().normalizedTimeTotalNanoseconds(), roundRecord.total()); } @TruffleBoundary @@ -2813,7 +2879,7 @@ public static TruffleString temporalInstantToString(JSContext ctx, JSRealm realm } var timeZoneRec = createTimeZoneMethodsRecordOnlyGetOffsetNanosecondsFor(realm, outputTimeZone); long offsetNs = getOffsetNanosecondsFor(ctx, realm, timeZoneRec, instant); - JSTemporalPlainDateTimeObject dateTime = builtinTimeZoneGetPlainDateTimeFor(ctx, realm, instant, TemporalConstants.ISO8601, offsetNs); + JSTemporalPlainDateTimeObject dateTime = builtinTimeZoneGetPlainDateTimeFor(ctx, realm, instant, ISO8601, offsetNs); TruffleString dateTimeString = JSTemporalPlainDateTime.temporalDateTimeToString(dateTime.getYear(), dateTime.getMonth(), dateTime.getDay(), dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond(), dateTime.getMillisecond(), dateTime.getMicrosecond(), dateTime.getNanosecond(), Undefined.instance, precision, ShowCalendar.NEVER); @@ -2968,23 +3034,6 @@ public static TruffleString temporalZonedDateTimeToString(JSContext ctx, JSRealm return temporalZonedDateTimeToString(ctx, realm, zonedDateTime, precision, showCalendar, showTimeZone, showOffset, null, Unit.EMPTY, RoundingMode.EMPTY); } - public static JSTemporalDateTimeRecord addDateTime(JSContext ctx, JSRealm realm, - int year, int month, int day, int hour, int minute, int second, - int millisecond, int microsecond, double nanosecond, - CalendarMethodsRecord calendarRec, - double years, double months, double weeks, double days, double hours, double minutes, double seconds, - double milliseconds, double microseconds, double nanoseconds, - JSDynamicObject options, - Node node, InlinedBranchProfile errorBranch) { - TimeRecord timeResult = addTimeDouble(hour, minute, second, millisecond, microsecond, nanosecond, - hours, minutes, seconds, milliseconds, microseconds, nanoseconds, node, errorBranch); - JSTemporalPlainDateObject datePart = JSTemporalPlainDate.create(ctx, realm, year, month, day, calendarRec.receiver(), node, errorBranch); - JSDynamicObject dateDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, years, months, weeks, days + timeResult.days(), 0L, 0L, 0L, 0L, 0L, 0L, node, errorBranch); - JSTemporalPlainDateObject addedDate = calendarDateAdd(calendarRec, datePart, dateDuration, options); - return JSTemporalDateTimeRecord.create(addedDate.getYear(), addedDate.getMonth(), addedDate.getDay(), - timeResult.hour(), timeResult.minute(), timeResult.second(), timeResult.millisecond(), timeResult.microsecond(), timeResult.nanosecond()); - } - public static int compareISODateTime(int year, int month, int day, int hours, int minutes, int seconds, int milliseconds, int microseconds, int nanoseconds, int year2, int month2, int day2, int hours2, int minutes2, int seconds2, int milliseconds2, int microseconds2, int nanoseconds2) { int date = compareISODate(year, month, day, year2, month2, day2); @@ -3086,10 +3135,10 @@ public static BigInt parseTemporalInstant(TruffleString string) { ParseISODateTimeResult result = parseTemporalInstantString(string); TruffleString offsetString = result.getTimeZoneResult().getOffsetString(); assert (offsetString != null); - BigInteger utc = getUTCEpochNanoseconds(result.getYear(), result.getMonth(), result.getDay(), result.getHour(), result.getMinute(), result.getSecond(), + BigInt utc = getUTCEpochNanoseconds(result.getYear(), result.getMonth(), result.getDay(), result.getHour(), result.getMinute(), result.getSecond(), result.getMillisecond(), result.getMicrosecond(), result.getNanosecond()); long offsetNanoseconds = parseTimeZoneOffsetString(offsetString); - BigInt instant = new BigInt(utc.subtract(BigInteger.valueOf(offsetNanoseconds))); + BigInt instant = utc.subtract(BigInt.valueOf(offsetNanoseconds)); if (!isValidEpochNanoseconds(instant)) { throw TemporalErrors.createRangeErrorInvalidNanoseconds(); } @@ -3138,10 +3187,10 @@ public static JSTemporalInstantObject disambiguatePossibleInstants(JSContext ctx if (Disambiguation.REJECT == disambiguation) { throw Errors.createRangeError("disambiguation failed"); } - BigInteger epochNanoseconds = getUTCEpochNanoseconds(dateTime.getYear(), dateTime.getMonth(), dateTime.getDay(), dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond(), + BigInt epochNanoseconds = getUTCEpochNanoseconds(dateTime.getYear(), dateTime.getMonth(), dateTime.getDay(), dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond(), dateTime.getMillisecond(), dateTime.getMicrosecond(), dateTime.getNanosecond()); - JSTemporalInstantObject dayBefore = JSTemporalInstant.create(ctx, realm, new BigInt(epochNanoseconds.subtract(BI_8_64_13))); - JSTemporalInstantObject dayAfter = JSTemporalInstant.create(ctx, realm, new BigInt(epochNanoseconds.add(BI_8_64_13))); + JSTemporalInstantObject dayBefore = JSTemporalInstant.create(ctx, realm, epochNanoseconds.subtract(BI_NS_PER_DAY)); + JSTemporalInstantObject dayAfter = JSTemporalInstant.create(ctx, realm, epochNanoseconds.add(BI_NS_PER_DAY)); long offsetBefore = getOffsetNanosecondsFor(ctx, realm, timeZoneRec, dayBefore); long offsetAfter = getOffsetNanosecondsFor(ctx, realm, timeZoneRec, dayAfter); long nanoseconds = offsetAfter - offsetBefore; @@ -3194,8 +3243,8 @@ public static BigInt interpretISODateTimeOffset(JSContext ctx, JSRealm realm, in return instant.getNanoseconds(); } if (offsetBehaviour == OffsetBehaviour.EXACT || OffsetOption.USE == offsetOption) { - BigInteger epochNanoseconds = getUTCEpochNanoseconds(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond); - return new BigInt(epochNanoseconds.subtract(BigInteger.valueOf((long) offsetNs))); + BigInt epochNanoseconds = getUTCEpochNanoseconds(year, month, day, hour, minute, second, millisecond, microsecond, nanosecond); + return epochNanoseconds.subtract(BigInt.valueOf((long) offsetNs)); } assert offsetBehaviour == OffsetBehaviour.OPTION; assert OffsetOption.PREFER == offsetOption || OffsetOption.REJECT == offsetOption; @@ -3259,6 +3308,45 @@ public static BigInt addZonedDateTime(JSContext ctx, JSRealm realm, BigInt epoch return addInstant(intermediateInstant.getNanoseconds(), hours, minutes, seconds, milliseconds, microseconds, nanoseconds); } + @TruffleBoundary + public static BigInt addZonedDateTime(JSContext ctx, JSRealm realm, BigInt epochNanoseconds, + TimeZoneMethodsRecord timeZoneRec, CalendarMethodsRecord calendarRec, + double years, double months, double weeks, double days, + BigInt norm, + JSTemporalPlainDateTimeObject precalculatedPlainDateTime) { + return addZonedDateTime(ctx, realm, epochNanoseconds, timeZoneRec, calendarRec, years, months, weeks, days, norm, + precalculatedPlainDateTime, Undefined.instance); + } + + @TruffleBoundary + public static BigInt addZonedDateTime(JSContext ctx, JSRealm realm, BigInt epochNanoseconds, + TimeZoneMethodsRecord timeZoneRec, CalendarMethodsRecord calendarRec, + double years, double months, double weeks, double days, + BigInt norm, + JSTemporalPlainDateTimeObject precalculatedPlainDateTime, JSDynamicObject options) { + if (years == 0 && months == 0 && weeks == 0 && days == 0) { + return addInstant(epochNanoseconds, norm); + } + JSTemporalInstantObject instant = JSTemporalInstant.create(ctx, realm, epochNanoseconds); + JSTemporalPlainDateTimeObject temporalDateTime = precalculatedPlainDateTime != null + ? precalculatedPlainDateTime + : builtinTimeZoneGetPlainDateTimeFor(ctx, realm, timeZoneRec, instant, calendarRec.receiver()); + if (years == 0 && months == 0 && weeks == 0) { + Overflow overflow = toTemporalOverflow(options); + BigInt intermediate = addDaysToZonedDateTime(ctx, realm, instant, temporalDateTime, timeZoneRec, (int) days, overflow).epochNanoseconds(); + return addInstant(intermediate, norm); + } + JSTemporalPlainDateObject datePart = JSTemporalPlainDate.create(ctx, realm, temporalDateTime.getYear(), temporalDateTime.getMonth(), temporalDateTime.getDay(), + calendarRec.receiver(), null, InlinedBranchProfile.getUncached()); + JSTemporalDurationObject dateDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, years, months, weeks, days, 0, 0, 0, 0, 0, 0, null, InlinedBranchProfile.getUncached()); + JSTemporalPlainDateObject addedDate = calendarDateAdd(calendarRec, datePart, dateDuration, options); + JSTemporalPlainDateTimeObject intermediateDateTime = JSTemporalPlainDateTime.create(ctx, realm, addedDate.getYear(), addedDate.getMonth(), addedDate.getDay(), + temporalDateTime.getHour(), temporalDateTime.getMinute(), temporalDateTime.getSecond(), + temporalDateTime.getMillisecond(), temporalDateTime.getMicrosecond(), temporalDateTime.getNanosecond(), calendarRec.receiver()); + JSTemporalInstantObject intermediateInstant = builtinTimeZoneGetInstantFor(ctx, realm, timeZoneRec, intermediateDateTime, Disambiguation.COMPATIBLE); + return addInstant(intermediateInstant.getNanoseconds(), norm); + } + public static JSTemporalZonedDateTimeObject moveRelativeZonedDateTime(JSContext ctx, JSRealm realm, JSTemporalZonedDateTimeObject zdt, CalendarMethodsRecord calendarRec, TimeZoneMethodsRecord timeZoneRec, long years, long months, long weeks, long days, From cb3043eeb9699593ec0faaf56c82a63647499dea Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 10 Jun 2024 10:59:41 +0200 Subject: [PATCH 020/265] Clean up BalanceTimeDuration. --- .../builtins/temporal/TimeDurationRecord.java | 25 +------------- .../truffle/js/runtime/util/TemporalUtil.java | 34 +++++++++---------- 2 files changed, 18 insertions(+), 41 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/TimeDurationRecord.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/TimeDurationRecord.java index 8f4a510aed3..3c224413732 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/TimeDurationRecord.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/TimeDurationRecord.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -51,27 +51,4 @@ public record TimeDurationRecord( double milliseconds, double microseconds, double nanoseconds) { - - public double getOverflow() { - if (Double.isInfinite(days)) { - return days; - } else if (Double.isInfinite(hours)) { - return hours; - } else if (Double.isInfinite(minutes)) { - return minutes; - } else if (Double.isInfinite(seconds)) { - return seconds; - } else if (Double.isInfinite(milliseconds)) { - return milliseconds; - } else if (Double.isInfinite(microseconds)) { - return microseconds; - } else if (Double.isInfinite(nanoseconds)) { - return nanoseconds; - } - return 0.0; - } - - public boolean isOverflow() { - return Double.isInfinite(getOverflow()); - } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java index a0c1f23237a..c8a4344a471 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java @@ -2055,25 +2055,16 @@ public static void rejectDurationSign(double years, double months, double weeks, } } - public static TimeDurationRecord balanceTimeDuration(BigInt nanoseconds, Unit largestUnit) { - TimeDurationRecord result = balancePossiblyInfiniteTimeDuration(nanoseconds, largestUnit); - if (result.isOverflow()) { - throw Errors.createRangeError("Time is infinite"); - } - return result; - } - @TruffleBoundary - private static TimeDurationRecord balancePossiblyInfiniteTimeDuration(BigInt nanoseconds, Unit largestUnit) { - BigInteger ns = nanoseconds.bigIntegerValue(); + public static TimeDurationRecord balanceTimeDuration(BigInt normalizedTimeDuration, Unit largestUnit) { BigInteger d = BigInteger.ZERO; BigInteger h = BigInteger.ZERO; BigInteger min = BigInteger.ZERO; BigInteger s = BigInteger.ZERO; BigInteger ms = BigInteger.ZERO; BigInteger us = BigInteger.ZERO; - double sign = ns.signum() < 0 ? -1 : 1; - ns = ns.abs(); + double sign = normalizedTimeDurationSign(normalizedTimeDuration); + BigInteger ns = normalizedTimeDurationAbs(normalizedTimeDuration).bigIntegerValue(); switch (largestUnit) { case YEAR, MONTH, WEEK, DAY -> { var qr = ns.divideAndRemainder(BI_1000); @@ -2150,13 +2141,21 @@ private static TimeDurationRecord balancePossiblyInfiniteTimeDuration(BigInt nan us = qr[0]; ns = qr[1]; } - case NANOSECOND -> { + default -> { + assert largestUnit == Unit.NANOSECOND : largestUnit; } - default -> throw Errors.shouldNotReachHereUnexpectedValue(largestUnit); } - return new TimeDurationRecord(d.doubleValue() * sign, - h.doubleValue() * sign, min.doubleValue() * sign, s.doubleValue() * sign, - ms.doubleValue() * sign, us.doubleValue() * sign, ns.doubleValue() * sign); + double days = d.doubleValue() * sign; + double hours = h.doubleValue() * sign; + double minutes = min.doubleValue() * sign; + double seconds = s.doubleValue() * sign; + double milliseconds = ms.doubleValue() * sign; + double microseconds = us.doubleValue() * sign; + double nanoseconds = ns.doubleValue() * sign; + if (!isValidDuration(0, 0, 0, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds)) { + throw Errors.createRangeError("Time is infinite"); + } + return new TimeDurationRecord(days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds); } public static JSDynamicObject toDynamicObject(Object obj) { @@ -2177,6 +2176,7 @@ public static JSDynamicObject toJSDynamicObject(Object item, Node node, InlinedB } } + @TruffleBoundary public static boolean isValidDuration(double years, double months, double weeks, double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds) { int sign = durationSign(years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, From 8675e19a627fc719c79c0eb9f863ebba2bf526e8 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 10 Jun 2024 11:03:52 +0200 Subject: [PATCH 021/265] Update test262 status (-87 failing). --- graal-js/test/test262.json | 348 ------------------------------------- 1 file changed, 348 deletions(-) diff --git a/graal-js/test/test262.json b/graal-js/test/test262.json index 323da830024..65ee3abb0de 100644 --- a/graal-js/test/test262.json +++ b/graal-js/test/test262.json @@ -1890,26 +1890,6 @@ "filePath" : "built-ins/Temporal/Duration/out-of-range.js", "status" : "FAIL", "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/add/calendar-dateadd-called-with-options-undefined.js", - "status" : "FAIL", - "comment" : "new failures 2024-04-12" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/add/calendar-dateuntil-called-with-singular-largestunit.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/add/nanoseconds-is-number-max-safe-integer.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/add/order-of-operations.js", - "status" : "FAIL", - "comment" : "new failures 2022-12-12" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/add/precision-exact-mathematical-values.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" }, { "filePath" : "built-ins/Temporal/Duration/prototype/add/relativeto-propertybag-invalid-offset-string.js", "status" : "FAIL", @@ -1934,50 +1914,10 @@ "filePath" : "built-ins/Temporal/Duration/prototype/add/relativeto-sub-minute-offset.js", "status" : "FAIL", "comment" : "Temporal failures" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/calendar-dateadd-called-with-options-undefined.js", - "status" : "FAIL", - "comment" : "new failures 2024-06-07" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/calendar-dateuntil-called-with-singular-largestunit.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/dateuntil-field.js", - "status" : "FAIL", - "comment" : "new failures 2024-06-07" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/dst-balancing-result.js", - "status" : "FAIL", - "comment" : "new failures 2024-06-07" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/dst-rounding-result.js", - "status" : "FAIL", - "comment" : "new failures 2024-04-12" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/largestunit-smallestunit-combinations-relativeto.js", - "status" : "FAIL", - "comment" : "new failures 2024-06-07" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/largestunit-smallestunit-default.js", - "status" : "FAIL", - "comment" : "new failures 2022-05-20" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/order-of-operations.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/out-of-range-when-adjusting-rounded-days.js", - "status" : "FAIL", - "comment" : "new failures 2024-04-12" }, { "filePath" : "built-ins/Temporal/Duration/prototype/round/out-of-range-when-converting-from-normalized-duration.js", "status" : "FAIL", "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/precision-exact-in-round-duration.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" }, { "filePath" : "built-ins/Temporal/Duration/prototype/round/relativeto-propertybag-invalid-offset-string.js", "status" : "FAIL", @@ -2002,74 +1942,6 @@ "filePath" : "built-ins/Temporal/Duration/prototype/round/relativeto-sub-minute-offset.js", "status" : "FAIL", "comment" : "Temporal failures" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/round-negative-result.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/roundingmode-ceil.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/roundingmode-expand.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/roundingmode-floor.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/roundingmode-halfCeil.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/roundingmode-halfEven.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/roundingmode-halfExpand.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/roundingmode-halfFloor.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/roundingmode-halfTrunc.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/roundingmode-trunc.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/timezone-getpossibleinstantsfor-iterable.js", - "status" : "FAIL", - "comment" : "new failures 2024-06-07" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/total-duration-nanoseconds-too-large-with-zoned-datetime.js", - "status" : "FAIL", - "comment" : "new failures 2022-08-08" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/subtract/calendar-dateadd-called-with-options-undefined.js", - "status" : "FAIL", - "comment" : "new failures 2024-04-12" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/subtract/calendar-dateuntil-called-with-singular-largestunit.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/subtract/nanoseconds-is-number-max-safe-integer.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/subtract/order-of-operations.js", - "status" : "FAIL", - "comment" : "new failures 2022-12-12" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/subtract/precision-exact-mathematical-values.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" }, { "filePath" : "built-ins/Temporal/Duration/prototype/subtract/relativeto-propertybag-invalid-offset-string.js", "status" : "FAIL", @@ -2094,38 +1966,6 @@ "filePath" : "built-ins/Temporal/Duration/prototype/subtract/relativeto-sub-minute-offset.js", "status" : "FAIL", "comment" : "Temporal failures" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/toString/throws-when-rounded-duration-is-invalid.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/total/balance-negative-result.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/total/calendar-dateuntil-called-with-singular-largestunit.js", - "status" : "FAIL", - "comment" : "new failures 2024-06-07" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/total/dst-balancing-result.js", - "status" : "FAIL", - "comment" : "new failures 2024-06-07" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/total/dst-day-length.js", - "status" : "FAIL", - "comment" : "new failures 2024-06-07" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/total/dst-rounding-result.js", - "status" : "FAIL", - "comment" : "new failures 2024-04-12" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/total/duration-out-of-range-added-to-relativeto.js", - "status" : "FAIL", - "comment" : "new failures 2024-04-12" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/total/order-of-operations.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" }, { "filePath" : "built-ins/Temporal/Duration/prototype/total/precision-exact-mathematical-values-3.js", "status" : "FAIL", @@ -2134,18 +1974,6 @@ "filePath" : "built-ins/Temporal/Duration/prototype/total/precision-exact-mathematical-values-4.js", "status" : "FAIL", "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/total/precision-exact-mathematical-values-6.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/total/precision-exact-mathematical-values-7.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/total/relativeto-plaindate-add24hourdaystonormalizedtimeduration-out-of-range.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" }, { "filePath" : "built-ins/Temporal/Duration/prototype/total/relativeto-propertybag-invalid-offset-string.js", "status" : "FAIL", @@ -2170,22 +1998,6 @@ "filePath" : "built-ins/Temporal/Duration/prototype/total/relativeto-sub-minute-offset.js", "status" : "FAIL", "comment" : "Temporal failures" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/total/relativeto-zoneddatetime-with-fractional-days-different-sign.js", - "status" : "FAIL", - "comment" : "new failures 2022-08-08" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/total/relativeto-zoneddatetime-with-fractional-days.js", - "status" : "FAIL", - "comment" : "new failures 2022-08-08" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/total/total-of-each-unit-relativeto.js", - "status" : "FAIL", - "comment" : "new failures 2024-06-07" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/total/total-of-each-unit.js", - "status" : "FAIL", - "comment" : "new failures 2024-06-07" }, { "filePath" : "built-ins/Temporal/Instant/compare/argument-string-date-with-utc-offset.js", "status" : "FAIL", @@ -2354,18 +2166,10 @@ "filePath" : "built-ins/Temporal/PlainDate/prototype/monthsInYear/validate-calendar-value.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" }, { "filePath" : "built-ins/Temporal/PlainDate/prototype/since/order-of-operations.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/since/round-cross-unit-boundary.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-30" }, { "filePath" : "built-ins/Temporal/PlainDate/prototype/since/wrapping-at-end-of-month.js", "status" : "FAIL", @@ -2414,18 +2218,10 @@ "filePath" : "built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getpossibleinstantsfor.js", "status" : "FAIL", "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" }, { "filePath" : "built-ins/Temporal/PlainDate/prototype/until/order-of-operations.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/until/round-cross-unit-boundary.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-30" }, { "filePath" : "built-ins/Temporal/PlainDate/prototype/until/wrapping-at-end-of-month.js", "status" : "FAIL", @@ -2474,10 +2270,6 @@ "filePath" : "built-ins/Temporal/PlainDateTime/from/overflow-wrong-type.js", "status" : "FAIL", "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/add/order-of-operations.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" }, { "filePath" : "built-ins/Temporal/PlainDateTime/prototype/day/validate-calendar-value.js", "status" : "FAIL", @@ -2590,30 +2382,10 @@ "filePath" : "built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfTrunc.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateuntil-called-with-null-prototype-options.js", - "status" : "FAIL", - "comment" : "dateUntil called twice instead of once" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateuntil-called-with-plaindate-calendar.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/since/order-of-operations.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" }, { "filePath" : "built-ins/Temporal/PlainDateTime/prototype/since/wrapping-at-end-of-month.js", "status" : "FAIL", "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/subtract/order-of-operations.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" }, { "filePath" : "built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/disambiguate-empty-possible-instants-with-datetime-near-limits.js", "status" : "FAIL", @@ -2638,22 +2410,6 @@ "filePath" : "built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/plain-date-time-near-limits.js", "status" : "FAIL", "comment" : "new failures 2022-08-08" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateuntil-called-with-null-prototype-options.js", - "status" : "FAIL", - "comment" : "dateUntil called twice instead of once" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateuntil-called-with-plaindate-calendar.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/until/order-of-operations.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" }, { "filePath" : "built-ins/Temporal/PlainDateTime/prototype/until/wrapping-at-end-of-month.js", "status" : "FAIL", @@ -2962,10 +2718,6 @@ "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/since/order-of-operations.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/since/round-cross-unit-boundary.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-30" }, { "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-arguments-extra-options.js", "status" : "FAIL", @@ -3022,10 +2774,6 @@ "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/until/order-of-operations.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/until/round-cross-unit-boundary.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-30" }, { "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/year/validate-calendar-value.js", "status" : "FAIL", @@ -3474,50 +3222,10 @@ "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/argument-string-date-with-utc-offset.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/calendar-dateadd-called-with-options-undefined.js", - "status" : "FAIL", - "comment" : "new failures 2024-06-07" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/calendar-dateuntil-called-with-singular-largestunit.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/dst-month-day-boundary.js", - "status" : "FAIL", - "comment" : "new failures 2024-04-12" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/dst-rounding-result.js", - "status" : "FAIL", - "comment" : "new failures 2024-04-12" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/find-intermediate-instant.js", - "status" : "FAIL", - "comment" : "new failures 2024-04-12" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/order-of-operations.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/round-cross-unit-boundary.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-30" }, { "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/roundingincrement-addition-out-of-range.js", "status" : "FAIL", "comment" : "new failures 2024-06-07" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/roundingmode-ceil.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/roundingmode-expand.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/roundingmode-floor.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" }, { "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/wrapping-at-end-of-month.js", "status" : "FAIL", @@ -3554,50 +3262,10 @@ "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/argument-string-date-with-utc-offset.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/calendar-dateadd-called-with-options-undefined.js", - "status" : "FAIL", - "comment" : "new failures 2024-06-07" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/calendar-dateuntil-called-with-singular-largestunit.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/dst-month-day-boundary.js", - "status" : "FAIL", - "comment" : "new failures 2024-04-12" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/dst-rounding-result.js", - "status" : "FAIL", - "comment" : "new failures 2024-04-12" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/find-intermediate-instant.js", - "status" : "FAIL", - "comment" : "new failures 2024-04-12" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/order-of-operations.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/round-cross-unit-boundary.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-30" }, { "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/roundingincrement-addition-out-of-range.js", "status" : "FAIL", "comment" : "new failures 2024-06-07" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/roundingmode-ceil.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/roundingmode-expand.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/roundingmode-floor.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" }, { "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/wrapping-at-end-of-month.js", "status" : "FAIL", @@ -4954,10 +4622,6 @@ "filePath" : "staging/Intl402/Temporal/old/datetime-toLocaleString.js", "status" : "FAIL", "comment" : "new failures 2023-11-17" - }, { - "filePath" : "staging/Intl402/Temporal/old/duration-arithmetic-dst.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-17" }, { "filePath" : "staging/Intl402/Temporal/old/hebrew-leap-months.js", "status" : "FAIL", @@ -5013,14 +4677,6 @@ "COMPILE_IMMEDIATELY" : "SKIP" }, "comment" : "Long-running in compile mode" - }, { - "filePath" : "staging/Temporal/Duration/old/round.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-17" - }, { - "filePath" : "staging/Temporal/Duration/old/total.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-17" }, { "filePath" : "staging/Temporal/Instant/old/limits.js", "status" : "FAIL", @@ -5057,10 +4713,6 @@ "filePath" : "staging/Temporal/ZonedDateTime/old/construction-and-properties.js", "status" : "FAIL", "comment" : "new failures 2023-11-17" - }, { - "filePath" : "staging/Temporal/ZonedDateTime/old/dst-math.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-17" }, { "filePath" : "staging/Temporal/ZonedDateTime/old/dst-properties.js", "status" : "FAIL", From 83a76a01a938ba02ea9a103e50f09d8381662225 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 10 Jun 2024 12:01:58 +0200 Subject: [PATCH 022/265] Fix getPossibleInstantsFor and disambiguatePossibleInstants. --- .../temporal/TemporalTimeZonePrototypeBuiltins.java | 3 +++ .../oracle/truffle/js/runtime/util/TemporalUtil.java | 11 ++++++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalTimeZonePrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalTimeZonePrototypeBuiltins.java index cbd9276411e..501ea24f680 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalTimeZonePrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalTimeZonePrototypeBuiltins.java @@ -305,6 +305,9 @@ protected JSDynamicObject getPossibleInstantsFor(JSTemporalTimeZoneObject timeZo dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond(), dateTime.getMillisecond(), dateTime.getMicrosecond(), dateTime.getNanosecond()); List possibleInstants = new ArrayList<>(); for (BigInt epochNanoseconds : possibleEpochNanoseconds) { + if (!TemporalUtil.isValidEpochNanoseconds(epochNanoseconds)) { + throw TemporalErrors.createRangeErrorInvalidNanoseconds(); + } JSDynamicObject instant = JSTemporalInstant.create(getContext(), realm, epochNanoseconds); possibleInstants.add(instant); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java index c8a4344a471..26ab8314437 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java @@ -3189,8 +3189,13 @@ public static JSTemporalInstantObject disambiguatePossibleInstants(JSContext ctx } BigInt epochNanoseconds = getUTCEpochNanoseconds(dateTime.getYear(), dateTime.getMonth(), dateTime.getDay(), dateTime.getHour(), dateTime.getMinute(), dateTime.getSecond(), dateTime.getMillisecond(), dateTime.getMicrosecond(), dateTime.getNanosecond()); - JSTemporalInstantObject dayBefore = JSTemporalInstant.create(ctx, realm, epochNanoseconds.subtract(BI_NS_PER_DAY)); - JSTemporalInstantObject dayAfter = JSTemporalInstant.create(ctx, realm, epochNanoseconds.add(BI_NS_PER_DAY)); + BigInt dayBeforeNs = epochNanoseconds.subtract(BI_NS_PER_DAY); + BigInt dayAfterNs = epochNanoseconds.add(BI_NS_PER_DAY); + if (!TemporalUtil.isValidEpochNanoseconds(dayBeforeNs) || !TemporalUtil.isValidEpochNanoseconds(dayAfterNs)) { + throw TemporalErrors.createRangeErrorInvalidNanoseconds(); + } + JSTemporalInstantObject dayBefore = JSTemporalInstant.create(ctx, realm, dayBeforeNs); + JSTemporalInstantObject dayAfter = JSTemporalInstant.create(ctx, realm, dayAfterNs); long offsetBefore = getOffsetNanosecondsFor(ctx, realm, timeZoneRec, dayBefore); long offsetAfter = getOffsetNanosecondsFor(ctx, realm, timeZoneRec, dayAfter); long nanoseconds = offsetAfter - offsetBefore; @@ -3438,7 +3443,7 @@ public static List getIANATimeZoneEpochValue(TruffleString identifier, l ZoneId zoneId = ZoneId.of(Strings.toJavaString(identifier)); long fractions = milliseconds * 1_000_000L + microseconds * 1_000L + nanoseconds; ZonedDateTime zdt = ZonedDateTime.of((int) isoYear, (int) isoMonth, (int) isoDay, (int) hours, (int) minutes, (int) seconds, (int) fractions, zoneId); - list.add(BigInt.valueOf(zdt.toEpochSecond() * 1_000_000_000L + fractions)); + list.add(BigInt.valueOf(zdt.toEpochSecond()).multiply(BigInt.valueOf(1_000_000_000L)).add(BigInt.valueOf(fractions))); } catch (Exception ex) { assert false; } From a87ab50f35824fa0eb67447b836269e3c74d675a Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 10 Jun 2024 12:08:50 +0200 Subject: [PATCH 023/265] Update test262 status (-13 failing). --- graal-js/test/test262.json | 52 -------------------------------------- 1 file changed, 52 deletions(-) diff --git a/graal-js/test/test262.json b/graal-js/test/test262.json index 65ee3abb0de..6eb634554d1 100644 --- a/graal-js/test/test262.json +++ b/graal-js/test/test262.json @@ -1966,14 +1966,6 @@ "filePath" : "built-ins/Temporal/Duration/prototype/subtract/relativeto-sub-minute-offset.js", "status" : "FAIL", "comment" : "Temporal failures" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/total/precision-exact-mathematical-values-3.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/total/precision-exact-mathematical-values-4.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" }, { "filePath" : "built-ins/Temporal/Duration/prototype/total/relativeto-propertybag-invalid-offset-string.js", "status" : "FAIL", @@ -2386,10 +2378,6 @@ "filePath" : "built-ins/Temporal/PlainDateTime/prototype/since/wrapping-at-end-of-month.js", "status" : "FAIL", "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/disambiguate-empty-possible-instants-with-datetime-near-limits.js", - "status" : "FAIL", - "comment" : "new failures 2022-08-08" }, { "filePath" : "built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/getoffsetnanosecondsfor-out-of-range-forward-offset-shift.js", "status" : "FAIL", @@ -2398,18 +2386,10 @@ "filePath" : "built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/getpossibleinstantsfor-out-of-range-backward-offset-shift.js", "status" : "FAIL", "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/invalid-instant.js", - "status" : "FAIL", - "comment" : "new failures 2022-05-20" }, { "filePath" : "built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/plain-custom-timezone.js", "status" : "FAIL", "comment" : "Temporal failures" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/plain-date-time-near-limits.js", - "status" : "FAIL", - "comment" : "new failures 2022-08-08" }, { "filePath" : "built-ins/Temporal/PlainDateTime/prototype/until/wrapping-at-end-of-month.js", "status" : "FAIL", @@ -2994,10 +2974,6 @@ "filePath" : "built-ins/Temporal/ZonedDateTime/from/zoneddatetime-string.js", "status" : "FAIL", "comment" : "Temporal failures" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/add/argument-duration-max.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" }, { "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/day/validate-calendar-value.js", "status" : "FAIL", @@ -3162,10 +3138,6 @@ "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/round/order-of-operations.js", "status" : "FAIL", "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/round/rounding-direction.js", - "status" : "FAIL", - "comment" : "new failures 2022-05-20" }, { "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/round/rounding-is-noop.js", "status" : "FAIL", @@ -3222,10 +3194,6 @@ "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/argument-string-date-with-utc-offset.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/roundingincrement-addition-out-of-range.js", - "status" : "FAIL", - "comment" : "new failures 2024-06-07" }, { "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/wrapping-at-end-of-month.js", "status" : "FAIL", @@ -3242,10 +3210,6 @@ "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/startOfDay/getpossibleinstantsfor-out-of-range-backward-offset-shift.js", "status" : "FAIL", "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/subtract/argument-duration-max.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" }, { "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/argument-propertybag-invalid-offset-string.js", "status" : "FAIL", @@ -3262,10 +3226,6 @@ "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/argument-string-date-with-utc-offset.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/roundingincrement-addition-out-of-range.js", - "status" : "FAIL", - "comment" : "new failures 2024-06-07" }, { "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/wrapping-at-end-of-month.js", "status" : "FAIL", @@ -3306,10 +3266,6 @@ "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/with/overflow-wrong-type.js", "status" : "FAIL", "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/with/zoned-datetime-like-at-minimum-date-time.js", - "status" : "FAIL", - "comment" : "new failures 2022-08-08" }, { "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/withCalendar/subclassing-ignored.js", "status" : "FAIL", @@ -4677,10 +4633,6 @@ "COMPILE_IMMEDIATELY" : "SKIP" }, "comment" : "Long-running in compile mode" - }, { - "filePath" : "staging/Temporal/Instant/old/limits.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-17" }, { "filePath" : "staging/Temporal/Regex/old/instant.js", "status" : "FAIL", @@ -4729,10 +4681,6 @@ "filePath" : "staging/Temporal/ZonedDateTime/old/string-parsing.js", "status" : "FAIL", "comment" : "new failures 2023-11-17" - }, { - "filePath" : "staging/Temporal/ZonedDateTime/old/toInstant.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-17" }, { "filePath" : "staging/Temporal/ZonedDateTime/old/toPlainDate.js", "status" : "FAIL", From f4c469ad0eefb4cc999ab16953c134e64313ebed Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 10 Jun 2024 12:20:02 +0200 Subject: [PATCH 024/265] Avoiding throwing exception when attempting to parse time zone offset string. --- .../truffle/js/runtime/util/TemporalUtil.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java index 26ab8314437..f49e4a286b6 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java @@ -1270,16 +1270,18 @@ public static JSTemporalTimeZoneObject createTemporalTimeZone(JSContext ctx, JSR return createTemporalTimeZone(ctx, realm, ctx.getTemporalTimeZoneFactory().getPrototype(realm), identifier); } + @TruffleBoundary public static JSTemporalTimeZoneObject createTemporalTimeZone(JSContext ctx, JSRealm realm, JSDynamicObject proto, TruffleString identifier) { BigInt offsetNs; TruffleString newIdentifier = identifier; - try { - long result = parseTimeZoneOffsetString(identifier); + JSTemporalParserRecord rec = new TemporalParser(identifier).parseTimeZoneNumericUTCOffset(); + if (rec != null) { // no abrupt completion + long result = parseTimeZoneOffsetNs(rec); newIdentifier = formatTimeZoneOffsetString(result); offsetNs = BigInt.valueOf(result); - } catch (Exception ex) { - assert canonicalizeTimeZoneName(identifier).equals(identifier); + } else { + assert canonicalizeTimeZoneName(identifier).equals(identifier) : identifier; offsetNs = null; } return JSTemporalTimeZone.create(ctx, realm, proto, offsetNs, newIdentifier); @@ -2937,11 +2939,14 @@ public static TruffleString formatTimeZoneOffsetString(long offsetNanosecondsPar @TruffleBoundary public static long parseTimeZoneOffsetString(TruffleString string) { - JSTemporalParserRecord rec = (new TemporalParser(string)).parseTimeZoneNumericUTCOffset(); + JSTemporalParserRecord rec = new TemporalParser(string).parseTimeZoneNumericUTCOffset(); if (rec == null) { throw Errors.createRangeError("TemporalTimeZoneNumericUTCOffset expected"); } + return parseTimeZoneOffsetNs(rec); + } + private static long parseTimeZoneOffsetNs(JSTemporalParserRecord rec) { long nanoseconds; if (rec.getOffsetFraction() == null) { nanoseconds = 0; From 5e302c0f1cbec89f73ed4b2d6198f6c2abc4d5d3 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 10 Jun 2024 14:19:13 +0200 Subject: [PATCH 025/265] Temporal cleanup: remove unused code. --- ...mporalBalanceDateDurationRelativeNode.java | 208 ------------------ .../TemporalMoveRelativeDateNode.java | 71 ------ .../ToTemporalTimeZoneSlotValueNode.java | 3 - .../temporal/MoveRelativeDateResult.java | 44 ---- .../truffle/js/runtime/util/TemporalUtil.java | 94 -------- 5 files changed, 420 deletions(-) delete mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalBalanceDateDurationRelativeNode.java delete mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalMoveRelativeDateNode.java delete mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/MoveRelativeDateResult.java diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalBalanceDateDurationRelativeNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalBalanceDateDurationRelativeNode.java deleted file mode 100644 index 66b240fb26d..00000000000 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalBalanceDateDurationRelativeNode.java +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * The Universal Permissive License (UPL), Version 1.0 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or - * data (collectively the "Software"), free of charge and under any and all - * copyright rights in the Software, and any and all patent rights owned or - * freely licensable by each licensor hereunder covering either (i) the - * unmodified Software as contributed to or provided by such licensor, or (ii) - * the Larger Works (as defined below), to deal in both - * - * (a) the Software, and - * - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * - * The above copyright notice and either this complete permission notice or at a - * minimum a reference to the UPL must be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.oracle.truffle.js.nodes.temporal; - -import com.oracle.truffle.api.CompilerDirectives; -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.ImportStatic; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.profiles.InlinedBranchProfile; -import com.oracle.truffle.api.profiles.InlinedConditionProfile; -import com.oracle.truffle.api.strings.TruffleString; -import com.oracle.truffle.js.nodes.JavaScriptBaseNode; -import com.oracle.truffle.js.nodes.access.CreateDataPropertyNode; -import com.oracle.truffle.js.nodes.function.JSFunctionCallNode; -import com.oracle.truffle.js.runtime.Errors; -import com.oracle.truffle.js.runtime.JSArguments; -import com.oracle.truffle.js.runtime.JSContext; -import com.oracle.truffle.js.runtime.JSRealm; -import com.oracle.truffle.js.runtime.builtins.JSOrdinary; -import com.oracle.truffle.js.runtime.builtins.temporal.CalendarMethodsRecord; -import com.oracle.truffle.js.runtime.builtins.temporal.DateDurationRecord; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalCalendar; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDuration; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationObject; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateObject; -import com.oracle.truffle.js.runtime.objects.JSDynamicObject; -import com.oracle.truffle.js.runtime.objects.JSObject; -import com.oracle.truffle.js.runtime.util.TemporalConstants; -import com.oracle.truffle.js.runtime.util.TemporalErrors; -import com.oracle.truffle.js.runtime.util.TemporalUtil; -import com.oracle.truffle.js.runtime.util.TemporalUtil.Unit; - -/** - * Implementation of the Temporal balanceDurationRelative operation. - */ -@ImportStatic(TemporalConstants.class) -public abstract class TemporalBalanceDateDurationRelativeNode extends JavaScriptBaseNode { - - @Child private JSFunctionCallNode callDateAddNode; - @Child private JSFunctionCallNode callDateUntilNode; - - protected TemporalBalanceDateDurationRelativeNode() { - } - - public abstract DateDurationRecord execute(double years, double months, double weeks, double days, - TemporalUtil.Unit largestUnit, TemporalUtil.Unit smallestUnit, JSTemporalPlainDateObject plainRelativeTo, CalendarMethodsRecord calendarRec); - - @Specialization - protected DateDurationRecord balanceDurationRelative(double years, double months, double weeks, double days, - Unit largestUnit, Unit smallestUnit, JSTemporalPlainDateObject plainRelativeTo, CalendarMethodsRecord calendarRec, - @Cached InlinedBranchProfile errorBranch, - @Cached InlinedBranchProfile unitIsYear, - @Cached InlinedBranchProfile unitIsMonth, - @Cached InlinedBranchProfile unitIsWeek, - @Cached InlinedConditionProfile unitIsDay, - @Cached("create(getLanguage().getJSContext(), LARGEST_UNIT)") CreateDataPropertyNode createLargestUnitProperty) { - boolean allZero = (years == 0 && months == 0 && weeks == 0 && days == 0); - if (unitIsDay.profile(this, (largestUnit != TemporalUtil.Unit.YEAR && largestUnit != TemporalUtil.Unit.MONTH && largestUnit != TemporalUtil.Unit.WEEK) || allZero)) { - return new DateDurationRecord(years, months, weeks, days); - } - if (plainRelativeTo == null) { - errorBranch.enter(this); - throw TemporalErrors.createRangeErrorRelativeToNotUndefined(); - } - - JSContext ctx = getLanguage().getJSContext(); - JSRealm realm = getRealm(); - JSObject untilOptions = JSOrdinary.createWithNullPrototype(ctx); - createLargestUnitProperty.executeVoid(untilOptions, largestUnit.toTruffleString()); - - switch (largestUnit) { - case YEAR -> { - unitIsYear.enter(this); - return getUnitYear(years, months, weeks, days, smallestUnit, plainRelativeTo, calendarRec, untilOptions, - this, errorBranch, ctx, realm); - } - case MONTH -> { - unitIsMonth.enter(this); - return getUnitMonth(years, months, weeks, days, smallestUnit, plainRelativeTo, calendarRec, untilOptions, - this, errorBranch, ctx, realm); - } - case WEEK -> { - unitIsWeek.enter(this); - return getUnitWeek(years, months, weeks, days, plainRelativeTo, calendarRec, untilOptions, - this, errorBranch, ctx, realm); - } - default -> throw Errors.shouldNotReachHereUnexpectedValue(largestUnit); - } - } - - private DateDurationRecord getUnitYear(double years, double months, double weeks, double days, Unit smallestUnit, - JSTemporalPlainDateObject plainRelativeTo, CalendarMethodsRecord calendarRec, JSObject untilOptions, - Node node, InlinedBranchProfile errorBranch, JSContext ctx, JSRealm realm) { - if (smallestUnit == Unit.WEEK) { - assert days == 0 : days; - var yearsMonthsDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, - years, months, 0, 0, 0, 0, 0, 0, 0, 0, this, errorBranch); - var later = calendarDateAdd(calendarRec, plainRelativeTo, yearsMonthsDuration, node, errorBranch, ctx, realm); - var untilResult = calendarDateUntil(calendarRec, plainRelativeTo, later, untilOptions, ctx, realm); - return new DateDurationRecord(untilResult.getYears(), untilResult.getMonths(), weeks, days); - } else { - var yearsMonthsWeeksDaysDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, - years, months, weeks, days, 0, 0, 0, 0, 0, 0, this, errorBranch); - var later = calendarDateAdd(calendarRec, plainRelativeTo, yearsMonthsWeeksDaysDuration, node, errorBranch, ctx, realm); - var untilResult = calendarDateUntil(calendarRec, plainRelativeTo, later, untilOptions, ctx, realm); - return new DateDurationRecord(untilResult.getYears(), untilResult.getMonths(), untilResult.getWeeks(), untilResult.getDays()); - } - } - - private DateDurationRecord getUnitMonth(double years, double months, double weeks, double days, Unit smallestUnit, - JSTemporalPlainDateObject plainRelativeTo, CalendarMethodsRecord calendarRec, JSObject untilOptions, - Node node, InlinedBranchProfile errorBranch, JSContext ctx, JSRealm realm) { - assert years == 0 : years; - if (smallestUnit == Unit.WEEK) { - assert days == 0 : days; - return new DateDurationRecord(years, months, weeks, days); - } else { - var monthsWeeksDaysDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, - years, months, weeks, days, 0, 0, 0, 0, 0, 0, this, errorBranch); - var later = calendarDateAdd(calendarRec, plainRelativeTo, monthsWeeksDaysDuration, node, errorBranch, ctx, realm); - var untilResult = calendarDateUntil(calendarRec, plainRelativeTo, later, untilOptions, ctx, realm); - return new DateDurationRecord(years, untilResult.getMonths(), untilResult.getWeeks(), untilResult.getDays()); - } - } - - private DateDurationRecord getUnitWeek(double years, double months, double weeks, double days, - JSTemporalPlainDateObject plainRelativeTo, CalendarMethodsRecord calendarRec, JSObject untilOptions, - Node node, InlinedBranchProfile errorBranch, JSContext ctx, JSRealm realm) { - assert years == 0 : years; - assert months == 0 : months; - var weeksDaysDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, - years, months, weeks, days, 0, 0, 0, 0, 0, 0, this, errorBranch); - var later = calendarDateAdd(calendarRec, plainRelativeTo, weeksDaysDuration, node, errorBranch, ctx, realm); - var untilResult = calendarDateUntil(calendarRec, plainRelativeTo, later, untilOptions, ctx, realm); - return new DateDurationRecord(years, months, untilResult.getWeeks(), untilResult.getDays()); - } - - protected JSTemporalPlainDateObject calendarDateAdd(CalendarMethodsRecord calendarRec, JSTemporalPlainDateObject plainDate, JSTemporalDurationObject duration, - Node node, InlinedBranchProfile errorBranch, JSContext ctx, JSRealm realm) { - if (callDateAddNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - callDateAddNode = insert(JSFunctionCallNode.createCall()); - } - Object calendar = toCalendarObject(calendarRec.receiver(), ctx, realm); - Object addedDate = callDateAddNode.executeCall(JSArguments.create(calendar, calendarRec.dateAdd(), plainDate, duration)); - return TemporalUtil.requireTemporalDate(addedDate, node, errorBranch); - } - - protected JSTemporalDurationObject calendarDateUntil(CalendarMethodsRecord calendarRec, JSTemporalPlainDateObject one, JSTemporalPlainDateObject two, JSDynamicObject options, - JSContext ctx, JSRealm realm) { - if (callDateUntilNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - callDateUntilNode = insert(JSFunctionCallNode.createCall()); - } - Object calendar = toCalendarObject(calendarRec.receiver(), ctx, realm); - Object addedDate = callDateUntilNode.executeCall(JSArguments.create(calendar, calendarRec.dateUntil(), one, two, options)); - return TemporalUtil.requireTemporalDuration(addedDate); - } - - private static Object toCalendarObject(Object calendarSlotValue, JSContext ctx, JSRealm realm) { - Object calendar; - if (calendarSlotValue instanceof TruffleString calendarID) { - calendar = JSTemporalCalendar.create(ctx, realm, calendarID); - } else { - calendar = calendarSlotValue; - } - return calendar; - } -} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalMoveRelativeDateNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalMoveRelativeDateNode.java deleted file mode 100644 index 9e87d3c2346..00000000000 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalMoveRelativeDateNode.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * The Universal Permissive License (UPL), Version 1.0 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or - * data (collectively the "Software"), free of charge and under any and all - * copyright rights in the Software, and any and all patent rights owned or - * freely licensable by each licensor hereunder covering either (i) the - * unmodified Software as contributed to or provided by such licensor, or (ii) - * the Larger Works (as defined below), to deal in both - * - * (a) the Software, and - * - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * - * The above copyright notice and either this complete permission notice or at a - * minimum a reference to the UPL must be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.oracle.truffle.js.nodes.temporal; - -import com.oracle.truffle.api.dsl.Cached; -import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.js.nodes.JavaScriptBaseNode; -import com.oracle.truffle.js.runtime.builtins.temporal.CalendarMethodsRecord; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationObject; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateObject; -import com.oracle.truffle.js.runtime.builtins.temporal.MoveRelativeDateResult; -import com.oracle.truffle.js.runtime.objects.Undefined; -import com.oracle.truffle.js.runtime.util.TemporalUtil; - -/** - * Implementation of the Temporal MoveRelativeDate operation. - */ -public abstract class TemporalMoveRelativeDateNode extends JavaScriptBaseNode { - - protected TemporalMoveRelativeDateNode() { - } - - public abstract MoveRelativeDateResult execute(CalendarMethodsRecord calendar, JSTemporalPlainDateObject relativeTo, JSTemporalDurationObject duration); - - @Specialization - protected MoveRelativeDateResult moveRelativeDate(CalendarMethodsRecord calendarRec, JSTemporalPlainDateObject relativeTo, JSTemporalDurationObject duration, - @Cached TemporalAddDateNode addDateNode) { - JSTemporalPlainDateObject newDate = addDateNode.execute(calendarRec, relativeTo, duration, Undefined.instance); - long days = TemporalUtil.daysUntil(relativeTo, newDate); - return new MoveRelativeDateResult(newDate, days); - } - -} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalTimeZoneSlotValueNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalTimeZoneSlotValueNode.java index 22ca01c6026..2c97846d169 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalTimeZoneSlotValueNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalTimeZoneSlotValueNode.java @@ -47,7 +47,6 @@ import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.nodes.JavaScriptBaseNode; import com.oracle.truffle.js.nodes.access.IsObjectNode; -import com.oracle.truffle.js.nodes.access.PropertyGetNode; import com.oracle.truffle.js.runtime.Errors; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalTimeZoneRecord; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalZonedDateTimeObject; @@ -59,8 +58,6 @@ */ public abstract class ToTemporalTimeZoneSlotValueNode extends JavaScriptBaseNode { - @Child protected PropertyGetNode getTimeZoneNode; - protected ToTemporalTimeZoneSlotValueNode() { } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/MoveRelativeDateResult.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/MoveRelativeDateResult.java deleted file mode 100644 index 0f264460583..00000000000 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/MoveRelativeDateResult.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * The Universal Permissive License (UPL), Version 1.0 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or - * data (collectively the "Software"), free of charge and under any and all - * copyright rights in the Software, and any and all patent rights owned or - * freely licensable by each licensor hereunder covering either (i) the - * unmodified Software as contributed to or provided by such licensor, or (ii) - * the Larger Works (as defined below), to deal in both - * - * (a) the Software, and - * - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * - * The above copyright notice and either this complete permission notice or at a - * minimum a reference to the UPL must be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.oracle.truffle.js.runtime.builtins.temporal; - -public record MoveRelativeDateResult(JSTemporalPlainDateObject relativeTo, long days) { -} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java index f49e4a286b6..5a1b6001c6f 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java @@ -257,7 +257,6 @@ public final class TemporalUtil { public static final Map unitMappingTime = createUnitMapping(singularTimeUnits); public static final Map unitMappingTimeOrDay = createUnitMapping(singularTimeUnits, DAY); public static final Map unitMappingTimeOrAuto = createUnitMapping(singularTimeUnits, AUTO); - public static final Map unitMappingTimeExceptHour = createUnitMapping(singularTimeUnits.subList(1, singularTimeUnits.size())); public static final Map unitMappingDateTime = createUnitMapping(singularDateTimeUnits); public static final Map unitMappingDateTimeOrAuto = createUnitMapping(singularDateTimeUnits, AUTO); public static final Map unitMappingYearMonth = createUnitMapping(singularYearMonthUnits); @@ -309,9 +308,6 @@ public final class TemporalUtil { public static final BigDecimal BD_10 = BigDecimal.valueOf(10); public static final BigDecimal BD_60 = BigDecimal.valueOf(60); public static final BigDecimal BD_1000 = BigDecimal.valueOf(1000); - public static final BigDecimal BD_10_POW_M_3 = new BigDecimal("0.001"); - public static final BigDecimal BD_10_POW_M_6 = new BigDecimal("0.000001"); - public static final BigDecimal BD_10_POW_M_9 = new BigDecimal("0.000000001"); public static final MathContext mc_20_floor = new MathContext(20, java.math.RoundingMode.FLOOR); @@ -1293,16 +1289,6 @@ public static TruffleString canonicalizeTimeZoneName(TruffleString timeZone) { return tzId == null ? null : Strings.fromJavaString(tzId); } - @TruffleBoundary - public static double getDouble(JSDynamicObject ob, TruffleString key, double defaultValue) { - Object value = JSObject.get(ob, key); - if (value == Undefined.instance) { - return defaultValue; - } - Number n = (Number) value; - return n.longValue(); - } - @TruffleBoundary public static boolean isoDateTimeWithinLimits(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond, int nanosecond) { if (-isoTimeBoundYears <= year && year <= isoTimeBoundYears) { @@ -1478,19 +1464,6 @@ public static Number toIntegerThrowOnInfinity(Object value) { return integer; } - @TruffleBoundary - public static double toIntegerWithoutRounding(Object argument) { - Number number = JSRuntime.toNumber(argument); - double dNumber = JSRuntime.doubleValue(number); - if (Double.isNaN(dNumber) || dNumber == 0.0d) { - return 0.0; - } - if (!JSRuntime.isIntegralNumber(dNumber)) { - throw Errors.createRangeError("value expected to be integer"); - } - return dNumber; - } - @TruffleBoundary public static Number toIntegerOrInfinity(Object value) { Number number = JSRuntime.toNumber(value); @@ -1504,11 +1477,6 @@ public static Number toIntegerOrInfinity(Object value) { return JSRuntime.truncateDouble(d); } - @TruffleBoundary - public static JSTemporalPlainDateObject calendarDateAdd(CalendarMethodsRecord calendarRec, JSTemporalPlainDateObject date, JSTemporalDurationObject duration) { - return calendarDateAdd(calendarRec, date, duration, Undefined.instance); - } - @TruffleBoundary public static JSTemporalPlainDateObject calendarDateAdd(CalendarMethodsRecord calendarRec, JSTemporalPlainDateObject date, JSTemporalDurationObject duration, JSDynamicObject options) { Object dateAddPrepared = calendarRec.dateAdd(); @@ -1525,11 +1493,6 @@ public static JSTemporalDurationObject calendarDateUntil(CalendarMethodsRecord c return requireTemporalDuration(date); } - private static JSTemporalDurationObject differenceDate(CalendarMethodsRecord calendarRec, JSDynamicObject one, JSDynamicObject two, JSDynamicObject untilOptions) { - // TODO - return calendarDateUntil(calendarRec, one, two, untilOptions); - } - public static Object toCalendarObject(Object calendarSlotValue) { Object calendar; if (calendarSlotValue instanceof TruffleString calendarID) { @@ -1857,38 +1820,6 @@ public static Unit largerOfTwoTemporalUnits(Unit a, Unit b) { return a.compareTo(b) <= 0 ? a : b; } - @TruffleBoundary - public static NormalizedDurationRecord differenceISODateTime(JSContext ctx, JSRealm realm, EnumerableOwnPropertyNamesNode namesNode, - int y1, int mon1, int d1, int h1, int min1, int s1, int ms1, int mus1, int ns1, - int y2, int mon2, int d2, int h2, int min2, int s2, int ms2, int mus2, int ns2, - CalendarMethodsRecord calendarRec, Unit largestUnit, JSDynamicObject options) { - assert options != null; - BigInt timeDuration = differenceTime(h1, min1, s1, ms1, mus1, ns1, h2, min2, s2, ms2, mus2, ns2); - int timeSign = normalizedTimeDurationSign(timeDuration); - int dateSign = compareISODate(y2, mon2, d2, y1, mon1, d1); - - ISODateRecord adjustedDate = createISODateRecord(y1, mon1, d1); - if (timeSign == -dateSign) { - adjustedDate = balanceISODate(adjustedDate.year(), adjustedDate.month(), adjustedDate.day() - timeSign); - timeDuration = add24HourDaysToNormalizedTimeDuration(timeDuration, -timeSign); - } - - JSDynamicObject date1 = JSTemporalPlainDate.create(ctx, realm, adjustedDate.year(), adjustedDate.month(), adjustedDate.day(), calendarRec.receiver(), null, - InlinedBranchProfile.getUncached()); - JSDynamicObject date2 = JSTemporalPlainDate.create(ctx, realm, y2, mon2, d2, calendarRec.receiver(), null, InlinedBranchProfile.getUncached()); - - Unit dateLargestUnit = largerOfTwoTemporalUnits(Unit.DAY, largestUnit); - JSObject untilOptions = mergeLargestUnitOption(ctx, namesNode, options, dateLargestUnit); - - JSTemporalDurationObject dateDifference = differenceDate(calendarRec, date1, date2, untilOptions); - double days = dateDifference.getDays(); - if (largestUnit != dateLargestUnit) { - timeDuration = add24HourDaysToNormalizedTimeDuration(timeDuration, days); - days = 0; - } - return createNormalizedDurationRecord(dateDifference.getYears(), dateDifference.getMonths(), dateDifference.getWeeks(), days, timeDuration); - } - public static DateDurationRecord createDateDurationRecord(double years, double months, double weeks, double days) { if (!isValidDuration(years, months, weeks, days, 0, 0, 0, 0, 0, 0)) { throw TemporalErrors.createTypeErrorDurationOutsideRange(); @@ -2288,15 +2219,6 @@ public static Unit defaultTemporalLargestUnit(double years, double months, doubl return Unit.NANOSECOND; } - @TruffleBoundary - public static double roundDurationCalculateFractionalSeconds(double seconds, double milliseconds, double microseconds, double nanoseconds) { - assert JSRuntime.isIntegralNumber(seconds) && JSRuntime.isIntegralNumber(milliseconds) && JSRuntime.isIntegralNumber(microseconds) && JSRuntime.isIntegralNumber(nanoseconds); - BigDecimal part1 = BigDecimal.valueOf(nanoseconds).multiply(BD_10_POW_M_9); - BigDecimal part2 = BigDecimal.valueOf(microseconds).multiply(BD_10_POW_M_6); - BigDecimal part3 = BigDecimal.valueOf(milliseconds).multiply(BD_10_POW_M_3); - return part1.add(part2).add(part3).add(BigDecimal.valueOf(seconds)).doubleValue(); - } - public record AddDaysToZonedDateTimeResult(BigInt epochNanoseconds, JSTemporalInstantObject instant, JSTemporalPlainDateTimeObject dateTime) { } @@ -3357,15 +3279,6 @@ public static BigInt addZonedDateTime(JSContext ctx, JSRealm realm, BigInt epoch return addInstant(intermediateInstant.getNanoseconds(), norm); } - public static JSTemporalZonedDateTimeObject moveRelativeZonedDateTime(JSContext ctx, JSRealm realm, JSTemporalZonedDateTimeObject zdt, - CalendarMethodsRecord calendarRec, TimeZoneMethodsRecord timeZoneRec, - long years, long months, long weeks, long days, - JSTemporalPlainDateTimeObject precalculatedPlainDateTime) { - BigInt intermediateNs = addZonedDateTime(ctx, realm, zdt.getNanoseconds(), timeZoneRec, calendarRec, years, months, weeks, days, 0, 0, 0, 0, 0, 0, - precalculatedPlainDateTime); - return JSTemporalZonedDateTime.create(ctx, realm, intermediateNs, zdt.getTimeZone(), zdt.getCalendar()); - } - public static boolean timeZoneEquals(Object tz1, Object tz2, ToTemporalTimeZoneIdentifierNode toTimeZoneIdentifier) { if (tz1 == tz2) { return true; @@ -3696,13 +3609,6 @@ public static int bitoi(BigInteger bi) { return bi.intValue(); } - @TruffleBoundary - public static double bitod(BigInteger bi) { - double value = bi.doubleValue(); - assert Double.isFinite(value); - return value; - } - @TruffleBoundary public static long bigIntToLong(BigInt val) { return val.longValueExact(); // throws From ccb2fa6b8bb4e931f9d06bc305c02c39b467f6fe Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 10 Jun 2024 14:34:31 +0200 Subject: [PATCH 026/265] Remove unused UnitPlural. --- .../truffle/js/runtime/util/TemporalUtil.java | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java index 5a1b6001c6f..4ff6e4a3a11 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java @@ -432,29 +432,6 @@ public boolean isTimeUnit() { } } - public enum UnitPlural { - YEARS(TemporalConstants.YEARS), - MONTHS(TemporalConstants.MONTHS), - WEEKS(TemporalConstants.WEEKS), - DAYS(TemporalConstants.DAYS), - HOURS(TemporalConstants.HOURS), - MINUTES(TemporalConstants.MINUTES), - SECONDS(TemporalConstants.SECONDS), - MILLISECONDS(TemporalConstants.MILLISECONDS), - MICROSECONDS(TemporalConstants.MICROSECONDS), - NANOSECONDS(TemporalConstants.NANOSECONDS); - - private final TruffleString name; - - UnitPlural(TruffleString name) { - this.name = name; - } - - public TruffleString toTruffleString() { - return name; - } - } - public enum RoundingMode { EMPTY, CEIL, From 8825f7586058d9a780406a33680fd7434ddbe084 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 10 Jun 2024 14:37:47 +0200 Subject: [PATCH 027/265] Share calendarDateAdd and calendarDateUntil and move them to TemporalUtil. --- ...mporalPlainYearMonthPrototypeBuiltins.java | 6 +++++- .../nodes/temporal/TemporalAddDateNode.java | 6 +----- .../temporal/TemporalDifferenceDateNode.java | 8 ++------ ...oralUnbalanceDateDurationRelativeNode.java | 14 +------------- .../truffle/js/runtime/util/TemporalUtil.java | 19 +++++++++++++++---- 5 files changed, 24 insertions(+), 29 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainYearMonthPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainYearMonthPrototypeBuiltins.java index c86d9710e79..4d576a19f1f 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainYearMonthPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalPlainYearMonthPrototypeBuiltins.java @@ -70,6 +70,7 @@ import com.oracle.truffle.js.nodes.cast.JSToIntegerThrowOnInfinityNode; import com.oracle.truffle.js.nodes.function.JSBuiltin; import com.oracle.truffle.js.nodes.function.JSBuiltinNode; +import com.oracle.truffle.js.nodes.function.JSFunctionCallNode; import com.oracle.truffle.js.nodes.temporal.CalendarMethodsRecordLookupNode; import com.oracle.truffle.js.nodes.temporal.GetDifferenceSettingsNode; import com.oracle.truffle.js.nodes.temporal.IsPartialTemporalObjectNode; @@ -82,6 +83,7 @@ import com.oracle.truffle.js.nodes.temporal.TemporalGetOptionNode; import com.oracle.truffle.js.nodes.temporal.TemporalYearMonthFromFieldsNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalCalendarIdentifierNode; +import com.oracle.truffle.js.nodes.temporal.ToTemporalCalendarObjectNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalDurationNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalYearMonthNode; import com.oracle.truffle.js.runtime.BigInt; @@ -538,6 +540,8 @@ protected JSTemporalDurationObject differenceTemporalPlainYearMonth(JSTemporalPl @Cached ToTemporalYearMonthNode toTemporalYearMonthNode, @Cached TemporalCalendarFieldsNode calendarFieldsNode, @Cached TemporalCalendarDateFromFieldsNode dateFromFieldsNode, + @Cached ToTemporalCalendarObjectNode toCalendarObject, + @Cached("createCall()") JSFunctionCallNode callDateUntil, @Cached InlinedBranchProfile errorBranch, @Cached InlinedConditionProfile optionUndefined) { JSTemporalPlainYearMonthObject other = toTemporalYearMonthNode.execute(otherParam, Undefined.instance); @@ -563,7 +567,7 @@ protected JSTemporalDurationObject differenceTemporalPlainYearMonth(JSTemporalPl TemporalUtil.createDataPropertyOrThrow(getContext(), thisFields, DAY, 1); JSTemporalPlainDateObject thisDate = dateFromFieldsNode.execute(calendarRec, thisFields, Undefined.instance); JSObject untilOptions = TemporalUtil.mergeLargestUnitOption(getContext(), namesNode, resolvedOptions, settings.largestUnit()); - JSTemporalDurationObject result = TemporalUtil.calendarDateUntil(calendarRec, thisDate, otherDate, untilOptions); + JSTemporalDurationObject result = TemporalUtil.calendarDateUntil(calendarRec, thisDate, otherDate, untilOptions, toCalendarObject, callDateUntil); JSRealm realm = getRealm(); NormalizedDurationRecord duration = TemporalUtil.createNormalizedDurationRecord(result.getYears(), result.getMonths(), 0, 0, TemporalUtil.zeroTimeDuration()); double durationYears = duration.years(); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalAddDateNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalAddDateNode.java index 213fdda5406..f8e004973d9 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalAddDateNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalAddDateNode.java @@ -46,7 +46,6 @@ import com.oracle.truffle.js.nodes.JavaScriptBaseNode; import com.oracle.truffle.js.nodes.function.JSFunctionCallNode; import com.oracle.truffle.js.runtime.BigInt; -import com.oracle.truffle.js.runtime.JSArguments; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRealm; import com.oracle.truffle.js.runtime.builtins.temporal.CalendarMethodsRecord; @@ -76,10 +75,7 @@ protected JSTemporalPlainDateObject addDate(CalendarMethodsRecord calendarRec, J @Cached InlinedBranchProfile errorBranch, @Cached TemporalGetOptionNode getOptionNode) { if (duration.getYears() != 0 || duration.getMonths() != 0 || duration.getWeeks() != 0) { - // CalendarDateAdd(calendarRec, plainDate, duration, options). - Object calendar = toCalendarObject.execute(calendarRec.receiver()); - Object addedDate = callDateAddNode.executeCall(JSArguments.create(calendar, calendarRec.dateAdd(), plainDate, duration, options)); - return TemporalUtil.requireTemporalDate(addedDate, this, errorBranch); + return TemporalUtil.calendarDateAdd(calendarRec, plainDate, duration, options, toCalendarObject, callDateAddNode); } else { JSContext ctx = getJSContext(); JSRealm realm = getRealm(); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalDifferenceDateNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalDifferenceDateNode.java index 34536aa5f7c..afcf59d9c36 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalDifferenceDateNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalDifferenceDateNode.java @@ -46,7 +46,6 @@ import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.js.nodes.JavaScriptBaseNode; import com.oracle.truffle.js.nodes.function.JSFunctionCallNode; -import com.oracle.truffle.js.runtime.JSArguments; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRealm; import com.oracle.truffle.js.runtime.builtins.temporal.CalendarMethodsRecord; @@ -77,7 +76,7 @@ final JSTemporalDurationObject differenceDate(CalendarMethodsRecord calendarRec, @Cached InlinedBranchProfile errorBranch, @Cached ToTemporalCalendarObjectNode toCalendarObject, @Cached("createCall()") JSFunctionCallNode callDateUntilNode) { - JSContext ctx = getLanguage().getJSContext(); + JSContext ctx = getJSContext(); JSRealm realm = getRealm(); if (one.getYear() == two.getYear() && one.getMonth() == two.getMonth() && one.getDay() == two.getDay()) { @@ -86,10 +85,7 @@ final JSTemporalDurationObject differenceDate(CalendarMethodsRecord calendarRec, double days = TemporalUtil.daysUntil(one, two); return JSTemporalDuration.createTemporalDuration(ctx, realm, 0, 0, 0, days, 0, 0, 0, 0, 0, 0, this, errorBranch); } else { - // CalendarDateUntil(calenderRec, one, two, options) - Object calendar = toCalendarObject.execute(calendarRec.receiver()); - Object addedDate = callDateUntilNode.executeCall(JSArguments.create(calendar, calendarRec.dateUntil(), one, two, untilOptions)); - return TemporalUtil.requireTemporalDuration(addedDate); + return TemporalUtil.calendarDateUntil(calendarRec, one, two, untilOptions, toCalendarObject, callDateUntilNode); } } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalUnbalanceDateDurationRelativeNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalUnbalanceDateDurationRelativeNode.java index bfbfef0af92..cfe5db3df09 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalUnbalanceDateDurationRelativeNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalUnbalanceDateDurationRelativeNode.java @@ -42,16 +42,13 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.js.nodes.JavaScriptBaseNode; import com.oracle.truffle.js.nodes.function.JSFunctionCallNode; -import com.oracle.truffle.js.runtime.JSArguments; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRealm; import com.oracle.truffle.js.runtime.builtins.temporal.CalendarMethodsRecord; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDuration; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationObject; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateObject; import com.oracle.truffle.js.runtime.objects.Undefined; import com.oracle.truffle.js.runtime.util.TemporalUtil; @@ -83,17 +80,8 @@ protected double unbalanceDurationRelative(double years, double months, double w JSRealm realm = getRealm(); var yearsMonthsWeeksDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, years, months, weeks, 0, 0, 0, 0, 0, 0, 0, this, errorBranch); - JSTemporalPlainDateObject later = calendarDateAdd(calendarRec, plainRelativeTo, yearsMonthsWeeksDuration, - this, errorBranch, toCalendarObjectNode, callDateAddNode); + JSTemporalPlainDateObject later = TemporalUtil.calendarDateAdd(calendarRec, plainRelativeTo, yearsMonthsWeeksDuration, Undefined.instance, toCalendarObjectNode, callDateAddNode); double yearsMonthsWeeksInDays = TemporalUtil.daysUntil(plainRelativeTo, later); return days + yearsMonthsWeeksInDays; } - - static JSTemporalPlainDateObject calendarDateAdd(CalendarMethodsRecord calendarRec, JSTemporalPlainDateObject date, JSTemporalDurationObject duration, - Node node, InlinedBranchProfile errorBranch, ToTemporalCalendarObjectNode toCalendarObjectNode, JSFunctionCallNode callDateAddNode) { - Object calendar = toCalendarObjectNode.execute(calendarRec.receiver()); - Object addedDate = callDateAddNode.executeCall(JSArguments.create(calendar, calendarRec.dateAdd(), date, duration, Undefined.instance)); - return TemporalUtil.requireTemporalDate(addedDate, node, errorBranch); - } - } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java index 4ff6e4a3a11..ffc02a096a6 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java @@ -127,18 +127,21 @@ import com.oracle.truffle.js.nodes.access.EnumerableOwnPropertyNamesNode; import com.oracle.truffle.js.nodes.cast.JSToIntegerOrInfinityNode; import com.oracle.truffle.js.nodes.cast.JSToIntegerThrowOnInfinityNode; +import com.oracle.truffle.js.nodes.function.JSFunctionCallNode; import com.oracle.truffle.js.nodes.temporal.CalendarMethodsRecordLookupNode; import com.oracle.truffle.js.nodes.temporal.TemporalCalendarDateFromFieldsNode; import com.oracle.truffle.js.nodes.temporal.TemporalCalendarGetterNode; import com.oracle.truffle.js.nodes.temporal.TemporalGetOptionNode; import com.oracle.truffle.js.nodes.temporal.ToFractionalSecondDigitsNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalCalendarIdentifierNode; +import com.oracle.truffle.js.nodes.temporal.ToTemporalCalendarObjectNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalCalendarSlotValueNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalTimeZoneIdentifierNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalTimeZoneSlotValueNode; import com.oracle.truffle.js.runtime.BigInt; import com.oracle.truffle.js.runtime.Boundaries; import com.oracle.truffle.js.runtime.Errors; +import com.oracle.truffle.js.runtime.JSArguments; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRealm; import com.oracle.truffle.js.runtime.JSRuntime; @@ -1462,11 +1465,19 @@ public static JSTemporalPlainDateObject calendarDateAdd(CalendarMethodsRecord ca return requireTemporalDate(addedDate); } - @TruffleBoundary - public static JSTemporalDurationObject calendarDateUntil(CalendarMethodsRecord calendarRec, JSDynamicObject one, JSDynamicObject two, JSDynamicObject options) { + public static JSTemporalPlainDateObject calendarDateAdd(CalendarMethodsRecord calendarRec, JSTemporalPlainDateObject date, JSTemporalDurationObject duration, JSDynamicObject options, + ToTemporalCalendarObjectNode toCalendarObject, JSFunctionCallNode callDateAdd) { + Object dateAddPrepared = calendarRec.dateAdd(); + Object calendar = toCalendarObject.execute(calendarRec.receiver()); + Object addedDate = callDateAdd.executeCall(JSArguments.create(calendar, dateAddPrepared, date, duration, options)); + return requireTemporalDate(addedDate); + } + + public static JSTemporalDurationObject calendarDateUntil(CalendarMethodsRecord calendarRec, JSTemporalPlainDateObject one, JSTemporalPlainDateObject two, JSObject options, + ToTemporalCalendarObjectNode toCalendarObject, JSFunctionCallNode callDateUntil) { Object dateUntilPrepared = calendarRec.dateUntil(); - Object calendar = toCalendarObject(calendarRec.receiver()); - Object date = JSRuntime.call(dateUntilPrepared, calendar, new Object[]{one, two, options}); + Object calendar = toCalendarObject.execute(calendarRec.receiver()); + Object date = callDateUntil.executeCall(JSArguments.create(calendar, dateUntilPrepared, one, two, options)); return requireTemporalDuration(date); } From 68ca25687adf4a625516fcfd77bb49d702f36af7 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 10 Jun 2024 15:09:48 +0200 Subject: [PATCH 028/265] Introduce TemporalAddZonedDateTimeNode. --- .../TemporalDurationFunctionBuiltins.java | 6 +- .../TemporalDurationPrototypeBuiltins.java | 14 +- ...emporalZonedDateTimePrototypeBuiltins.java | 19 ++- .../TemporalAddZonedDateTimeNode.java | 120 ++++++++++++++++++ .../truffle/js/runtime/util/TemporalUtil.java | 100 --------------- 5 files changed, 142 insertions(+), 117 deletions(-) create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalAddZonedDateTimeNode.java diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationFunctionBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationFunctionBuiltins.java index ad3495a554f..b670696dbf4 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationFunctionBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationFunctionBuiltins.java @@ -47,6 +47,7 @@ import com.oracle.truffle.js.builtins.JSBuiltinsContainer; import com.oracle.truffle.js.nodes.function.JSBuiltin; import com.oracle.truffle.js.nodes.temporal.CalendarMethodsRecordLookupNode; +import com.oracle.truffle.js.nodes.temporal.TemporalAddZonedDateTimeNode; import com.oracle.truffle.js.nodes.temporal.TemporalUnbalanceDateDurationRelativeNode; import com.oracle.truffle.js.nodes.temporal.ToRelativeTemporalObjectNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalDurationNode; @@ -134,6 +135,7 @@ protected int compare(Object oneParam, Object twoParam, Object optionsParam, @Cached("createDateAdd()") CalendarMethodsRecordLookupNode lookupDateAdd, @Cached ToRelativeTemporalObjectNode toRelativeTemporalObjectNode, @Cached TemporalUnbalanceDateDurationRelativeNode unbalanceDurationRelativeNode, + @Cached TemporalAddZonedDateTimeNode addZonedDateTimeNode, @Cached InlinedBranchProfile errorBranch, @Cached InlinedConditionProfile optionUndefined) { JSTemporalDurationObject one = toTemporalDurationNode.execute(oneParam); @@ -163,11 +165,11 @@ protected int compare(Object oneParam, Object twoParam, Object optionsParam, BigInt norm1 = TemporalUtil.normalizeTimeDuration(one.getHours(), one.getMinutes(), one.getSeconds(), one.getMilliseconds(), one.getMicroseconds(), one.getNanoseconds()); BigInt norm2 = TemporalUtil.normalizeTimeDuration(two.getHours(), two.getMinutes(), two.getSeconds(), two.getMilliseconds(), two.getMicroseconds(), two.getNanoseconds()); - var after1 = TemporalUtil.addZonedDateTime(getContext(), realm, + var after1 = addZonedDateTimeNode.execute( zonedRelativeTo.getNanoseconds(), timeZoneRec, calendarRec, one.getYears(), one.getMonths(), one.getWeeks(), one.getDays(), norm1, precalculatedPlainDateTime); - var after2 = TemporalUtil.addZonedDateTime(getContext(), realm, + var after2 = addZonedDateTimeNode.execute( zonedRelativeTo.getNanoseconds(), timeZoneRec, calendarRec, two.getYears(), two.getMonths(), two.getWeeks(), two.getDays(), norm2, precalculatedPlainDateTime); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java index fa7ff721095..c1db571aad6 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalDurationPrototypeBuiltins.java @@ -71,11 +71,12 @@ import com.oracle.truffle.js.nodes.function.JSBuiltinNode; import com.oracle.truffle.js.nodes.temporal.CalendarMethodsRecordLookupNode; import com.oracle.truffle.js.nodes.temporal.DifferencePlainDateTimeWithRoundingNode; -import com.oracle.truffle.js.nodes.temporal.DifferenceZonedDateTimeWithRoundingNode; import com.oracle.truffle.js.nodes.temporal.DifferenceZonedDateTimeNode; +import com.oracle.truffle.js.nodes.temporal.DifferenceZonedDateTimeWithRoundingNode; import com.oracle.truffle.js.nodes.temporal.GetRoundingIncrementOptionNode; import com.oracle.truffle.js.nodes.temporal.GetTemporalUnitNode; import com.oracle.truffle.js.nodes.temporal.TemporalAddDateNode; +import com.oracle.truffle.js.nodes.temporal.TemporalAddZonedDateTimeNode; import com.oracle.truffle.js.nodes.temporal.TemporalDifferenceDateNode; import com.oracle.truffle.js.nodes.temporal.TemporalGetOptionNode; import com.oracle.truffle.js.nodes.temporal.ToFractionalSecondDigitsNode; @@ -351,6 +352,7 @@ protected JSTemporalDurationObject addDurations(JSTemporalDurationObject duratio @Cached TemporalAddDateNode addDateNode, @Cached TemporalDifferenceDateNode differenceDateNode, @Cached DifferenceZonedDateTimeNode differenceZonedDateTimeNode, + @Cached TemporalAddZonedDateTimeNode addZonedDateTimeNode, @Cached InlinedBranchProfile errorBranch, @Cached InlinedConditionProfile optionUndefined, @Cached InlinedBranchProfile relativeToUndefinedBranch, @@ -436,9 +438,9 @@ protected JSTemporalDurationObject addDurations(JSTemporalDurationObject duratio var relativeToInstant = JSTemporalInstant.create(ctx, realm, zonedRelativeTo.getNanoseconds()); startDateTime = TemporalUtil.builtinTimeZoneGetPlainDateTimeFor(ctx, realm, timeZoneRec, relativeToInstant, calendarRec.receiver()); } - BigInt intermediateNs = TemporalUtil.addZonedDateTime(ctx, realm, zonedRelativeTo.getNanoseconds(), timeZoneRec, calendarRec, + BigInt intermediateNs = addZonedDateTimeNode.execute(zonedRelativeTo.getNanoseconds(), timeZoneRec, calendarRec, y1, mon1, w1, d1, norm1, startDateTime); - BigInt endNs = TemporalUtil.addZonedDateTime(ctx, realm, intermediateNs, timeZoneRec, calendarRec, + BigInt endNs = addZonedDateTimeNode.execute(intermediateNs, timeZoneRec, calendarRec, y2, mon2, w2, d2, norm2, null); if (largestUnit.isTimeUnit()) { @@ -491,6 +493,7 @@ protected JSTemporalDurationObject round(JSTemporalDurationObject duration, Obje @Cached TemporalAddDateNode addDate, @Cached DifferencePlainDateTimeWithRoundingNode differencePlainDateTimeWithRounding, @Cached DifferenceZonedDateTimeWithRoundingNode differenceZonedDateTimeWithRounding, + @Cached TemporalAddZonedDateTimeNode addZonedDateTimeNode, @Cached InlinedBranchProfile errorBranch, @Cached InlinedConditionProfile optionUndefined) { if (roundToParam == Undefined.instance) { @@ -583,7 +586,7 @@ protected JSTemporalDurationObject round(JSTemporalDurationObject duration, Obje JSTemporalDurationRecord roundResult; if (relativeToIsZonedDateTime.profile(node, zonedRelativeTo != null)) { BigInt relativeEpochNs = zonedRelativeTo.getNanoseconds(); - BigInt targetEpochNs = TemporalUtil.addZonedDateTime(ctx, realm, relativeEpochNs, timeZoneRec, calendarRec, + BigInt targetEpochNs = addZonedDateTimeNode.execute(relativeEpochNs, timeZoneRec, calendarRec, duration.getYears(), duration.getMonths(), duration.getWeeks(), duration.getDays(), norm, precalculatedPlainDateTime); @@ -642,6 +645,7 @@ protected final double total(JSTemporalDurationObject duration, Object totalOfPa @Cached TemporalAddDateNode addDate, @Cached DifferencePlainDateTimeWithRoundingNode differencePlainDateTimeWithRounding, @Cached DifferenceZonedDateTimeWithRoundingNode differenceZonedDateTimeWithRounding, + @Cached TemporalAddZonedDateTimeNode addZonedDateTimeNode, @Cached InlinedBranchProfile errorBranch, @Cached InlinedConditionProfile optionUndefined) { if (totalOfParam == Undefined.instance) { @@ -688,7 +692,7 @@ protected final double total(JSTemporalDurationObject duration, Object totalOfPa double total; if (zonedRelativeTo != null) { BigInt relativeEpochNs = zonedRelativeTo.getNanoseconds(); - BigInt targetEpochNs = TemporalUtil.addZonedDateTime(getContext(), realm, relativeEpochNs, timeZoneRec, calendarRec, + BigInt targetEpochNs = addZonedDateTimeNode.execute(relativeEpochNs, timeZoneRec, calendarRec, duration.getYears(), duration.getMonths(), duration.getWeeks(), duration.getDays(), norm, precalculatedPlainDateTime); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalZonedDateTimePrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalZonedDateTimePrototypeBuiltins.java index 9c750cfbdfc..f0cb60b8a2b 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalZonedDateTimePrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalZonedDateTimePrototypeBuiltins.java @@ -46,7 +46,6 @@ import static com.oracle.truffle.js.runtime.util.TemporalConstants.OFFSET; import static com.oracle.truffle.js.runtime.util.TemporalConstants.PREFER; import static com.oracle.truffle.js.runtime.util.TemporalUtil.dtoi; -import static com.oracle.truffle.js.runtime.util.TemporalUtil.dtol; import java.util.EnumSet; import java.util.List; @@ -84,7 +83,6 @@ import com.oracle.truffle.js.builtins.temporal.TemporalZonedDateTimePrototypeBuiltinsFactory.JSTemporalZonedDateTimeWithPlainTimeNodeGen; import com.oracle.truffle.js.builtins.temporal.TemporalZonedDateTimePrototypeBuiltinsFactory.JSTemporalZonedDateTimeWithTimeZoneNodeGen; import com.oracle.truffle.js.nodes.access.CreateDataPropertyNode; -import com.oracle.truffle.js.nodes.cast.JSNumberToBigIntNode; import com.oracle.truffle.js.nodes.function.JSBuiltin; import com.oracle.truffle.js.nodes.function.JSBuiltinNode; import com.oracle.truffle.js.nodes.temporal.CalendarMethodsRecordLookupNode; @@ -95,6 +93,7 @@ import com.oracle.truffle.js.nodes.temporal.GetTemporalUnitNode; import com.oracle.truffle.js.nodes.temporal.IsPartialTemporalObjectNode; import com.oracle.truffle.js.nodes.temporal.SnapshotOwnPropertiesNode; +import com.oracle.truffle.js.nodes.temporal.TemporalAddZonedDateTimeNode; import com.oracle.truffle.js.nodes.temporal.TemporalCalendarDateFromFieldsNode; import com.oracle.truffle.js.nodes.temporal.TemporalCalendarFieldsNode; import com.oracle.truffle.js.nodes.temporal.TemporalCalendarGetterNode; @@ -788,12 +787,12 @@ protected JSTemporalZonedDateTimeAddSubNode(JSContext context, JSBuiltin builtin @Specialization protected JSTemporalZonedDateTimeObject addDurationToOrSubtractDurationFromZonedDateTime( JSTemporalZonedDateTimeObject zonedDateTime, Object temporalDurationLike, Object optionsParam, - @Cached JSNumberToBigIntNode toBigInt, @Cached ToTemporalDurationNode toTemporalDurationNode, @Cached InlinedBranchProfile errorBranch, @Cached InlinedConditionProfile optionUndefined, @Cached("createDateAdd()") CalendarMethodsRecordLookupNode lookupDateAdd, - @Cached CreateTimeZoneMethodsRecordNode createTimeZoneMethodsRecord) { + @Cached CreateTimeZoneMethodsRecordNode createTimeZoneMethodsRecord, + @Cached TemporalAddZonedDateTimeNode addZonedDateTimeNode) { JSTemporalDurationObject duration = toTemporalDurationNode.execute(temporalDurationLike); JSDynamicObject options = getOptionsObject(optionsParam, this, errorBranch, optionUndefined); Object timeZone = zonedDateTime.getTimeZone(); @@ -802,12 +801,12 @@ protected JSTemporalZonedDateTimeObject addDurationToOrSubtractDurationFromZoned Object dateAddMethod = lookupDateAdd.execute(calendar); CalendarMethodsRecord calendarRec = CalendarMethodsRecord.forDateAdd(calendar, dateAddMethod); JSRealm realm = getRealm(); - BigInt epochNanoseconds = TemporalUtil.addZonedDateTime(getContext(), realm, zonedDateTime.getNanoseconds(), timeZoneRec, calendarRec, sign * dtol(duration.getYears()), - sign * dtol(duration.getMonths()), - sign * dtol(duration.getWeeks()), sign * dtol(duration.getDays()), sign * dtol(duration.getHours()), sign * dtol(duration.getMinutes()), sign * dtol(duration.getSeconds()), - sign * dtol(duration.getMilliseconds()), - sign * dtol(duration.getMicroseconds()), toBigInt.executeBigInt(sign * duration.getNanoseconds()).bigIntegerValue(), - null, options); + BigInt norm = TemporalUtil.normalizeTimeDuration( + sign * duration.getHours(), sign * duration.getMinutes(), sign * duration.getSeconds(), + sign * duration.getMilliseconds(), sign * duration.getMicroseconds(), sign * duration.getNanoseconds()); + BigInt epochNanoseconds = addZonedDateTimeNode.execute(zonedDateTime.getNanoseconds(), timeZoneRec, calendarRec, + sign * duration.getYears(), sign * duration.getMonths(), sign * duration.getWeeks(), sign * duration.getDays(), + norm, null, options); return JSTemporalZonedDateTime.create(getContext(), realm, epochNanoseconds, timeZone, calendar); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalAddZonedDateTimeNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalAddZonedDateTimeNode.java new file mode 100644 index 00000000000..ca9cc73d08a --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/TemporalAddZonedDateTimeNode.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.nodes.temporal; + +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.profiles.InlinedBranchProfile; +import com.oracle.truffle.js.nodes.JavaScriptBaseNode; +import com.oracle.truffle.js.nodes.function.JSFunctionCallNode; +import com.oracle.truffle.js.runtime.BigInt; +import com.oracle.truffle.js.runtime.JSContext; +import com.oracle.truffle.js.runtime.JSRealm; +import com.oracle.truffle.js.runtime.builtins.temporal.CalendarMethodsRecord; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDuration; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationObject; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalInstant; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalInstantObject; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDate; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateObject; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateTime; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateTimeObject; +import com.oracle.truffle.js.runtime.builtins.temporal.TimeZoneMethodsRecord; +import com.oracle.truffle.js.runtime.objects.JSDynamicObject; +import com.oracle.truffle.js.runtime.objects.Undefined; +import com.oracle.truffle.js.runtime.util.TemporalUtil; +import com.oracle.truffle.js.runtime.util.TemporalUtil.Disambiguation; +import com.oracle.truffle.js.runtime.util.TemporalUtil.Overflow; + +/** + * Implementation of the Temporal AddZonedDateTime operation. + */ +public abstract class TemporalAddZonedDateTimeNode extends JavaScriptBaseNode { + + protected TemporalAddZonedDateTimeNode() { + } + + public final BigInt execute(BigInt epochNanoseconds, + TimeZoneMethodsRecord timeZoneRec, CalendarMethodsRecord calendarRec, + double years, double months, double weeks, double days, BigInt norm, + JSTemporalPlainDateTimeObject precalculatedPlainDateTime) { + return execute(epochNanoseconds, timeZoneRec, calendarRec, years, months, weeks, days, norm, precalculatedPlainDateTime, Undefined.instance); + } + + public abstract BigInt execute(BigInt epochNanoseconds, + TimeZoneMethodsRecord timeZoneRec, CalendarMethodsRecord calendarRec, + double years, double months, double weeks, double days, BigInt norm, + JSTemporalPlainDateTimeObject precalculatedPlainDateTime, JSDynamicObject options); + + @Specialization + protected BigInt addZonedDateTime(BigInt epochNanoseconds, + TimeZoneMethodsRecord timeZoneRec, CalendarMethodsRecord calendarRec, + double years, double months, double weeks, double days, BigInt norm, + JSTemporalPlainDateTimeObject precalculatedPlainDateTime, JSDynamicObject options, + @Cached ToTemporalCalendarObjectNode toCalendarObject, + @Cached("createCall()") JSFunctionCallNode callDateAddNode, + @Cached InlinedBranchProfile errorBranch) { + JSContext ctx = getJSContext(); + JSRealm realm = getRealm(); + + if (years == 0 && months == 0 && weeks == 0 && days == 0) { + return TemporalUtil.addInstant(epochNanoseconds, norm); + } + JSTemporalInstantObject instant = JSTemporalInstant.create(ctx, realm, epochNanoseconds); + JSTemporalPlainDateTimeObject temporalDateTime = precalculatedPlainDateTime != null + ? precalculatedPlainDateTime + : TemporalUtil.builtinTimeZoneGetPlainDateTimeFor(ctx, realm, timeZoneRec, instant, calendarRec.receiver()); + if (years == 0 && months == 0 && weeks == 0) { + Overflow overflow = TemporalUtil.toTemporalOverflow(options); + BigInt intermediate = TemporalUtil.addDaysToZonedDateTime(ctx, realm, instant, temporalDateTime, timeZoneRec, (int) days, overflow).epochNanoseconds(); + return TemporalUtil.addInstant(intermediate, norm); + } + JSTemporalPlainDateObject datePart = JSTemporalPlainDate.create(ctx, realm, temporalDateTime.getYear(), temporalDateTime.getMonth(), temporalDateTime.getDay(), + calendarRec.receiver(), this, errorBranch); + JSTemporalDurationObject dateDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, years, months, weeks, days, 0, 0, 0, 0, 0, 0, this, errorBranch); + JSTemporalPlainDateObject addedDate = TemporalUtil.calendarDateAdd(calendarRec, datePart, dateDuration, options, toCalendarObject, callDateAddNode); + JSTemporalPlainDateTimeObject intermediateDateTime = JSTemporalPlainDateTime.create(ctx, realm, addedDate.getYear(), addedDate.getMonth(), addedDate.getDay(), + temporalDateTime.getHour(), temporalDateTime.getMinute(), temporalDateTime.getSecond(), + temporalDateTime.getMillisecond(), temporalDateTime.getMicrosecond(), temporalDateTime.getNanosecond(), calendarRec.receiver()); + JSTemporalInstantObject intermediateInstant = TemporalUtil.builtinTimeZoneGetInstantFor(ctx, realm, timeZoneRec, intermediateDateTime, Disambiguation.COMPATIBLE); + return TemporalUtil.addInstant(intermediateInstant.getNanoseconds(), norm); + } +} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java index ffc02a096a6..e58a57d65e6 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java @@ -123,7 +123,6 @@ import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.api.strings.TruffleStringBuilderUTF16; -import com.oracle.truffle.js.lang.JavaScriptLanguage; import com.oracle.truffle.js.nodes.access.EnumerableOwnPropertyNamesNode; import com.oracle.truffle.js.nodes.cast.JSToIntegerOrInfinityNode; import com.oracle.truffle.js.nodes.cast.JSToIntegerThrowOnInfinityNode; @@ -156,13 +155,11 @@ import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalCalendar; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalCalendarObject; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDateTimeRecord; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDuration; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationObject; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationRecord; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalInstant; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalInstantObject; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalParserRecord; -import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDate; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateObject; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateTime; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainDateTimeObject; @@ -1457,14 +1454,6 @@ public static Number toIntegerOrInfinity(Object value) { return JSRuntime.truncateDouble(d); } - @TruffleBoundary - public static JSTemporalPlainDateObject calendarDateAdd(CalendarMethodsRecord calendarRec, JSTemporalPlainDateObject date, JSTemporalDurationObject duration, JSDynamicObject options) { - Object dateAddPrepared = calendarRec.dateAdd(); - Object calendar = toCalendarObject(calendarRec.receiver()); - Object addedDate = JSRuntime.call(dateAddPrepared, calendar, new Object[]{date, duration, options}); - return requireTemporalDate(addedDate); - } - public static JSTemporalPlainDateObject calendarDateAdd(CalendarMethodsRecord calendarRec, JSTemporalPlainDateObject date, JSTemporalDurationObject duration, JSDynamicObject options, ToTemporalCalendarObjectNode toCalendarObject, JSFunctionCallNode callDateAdd) { Object dateAddPrepared = calendarRec.dateAdd(); @@ -1481,16 +1470,6 @@ public static JSTemporalDurationObject calendarDateUntil(CalendarMethodsRecord c return requireTemporalDuration(date); } - public static Object toCalendarObject(Object calendarSlotValue) { - Object calendar; - if (calendarSlotValue instanceof TruffleString calendarID) { - calendar = JSTemporalCalendar.create(JavaScriptLanguage.get(null).getJSContext(), JavaScriptLanguage.getCurrentJSRealm(), calendarID); - } else { - calendar = calendarSlotValue; - } - return calendar; - } - @TruffleBoundary public static BigInt roundTemporalInstant(BigInt ns, int increment, Unit unit, RoundingMode roundingMode) { BigInt incrementNs = BigInt.valueOf(increment); @@ -3188,85 +3167,6 @@ public static BigInt interpretISODateTimeOffset(JSContext ctx, JSRealm realm, in return instant.getNanoseconds(); } - @TruffleBoundary - public static BigInt addZonedDateTime(JSContext ctx, JSRealm realm, BigInt epochNanoseconds, - TimeZoneMethodsRecord timeZoneRec, CalendarMethodsRecord calendarRec, - long years, long months, long weeks, long days, - long hours, long minutes, long seconds, long milliseconds, long microseconds, long nanoseconds, - JSTemporalPlainDateTimeObject precalculatedPlainDateTime) { - return addZonedDateTime(ctx, realm, epochNanoseconds, timeZoneRec, calendarRec, years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, - BigInteger.valueOf(nanoseconds), - precalculatedPlainDateTime, Undefined.instance); - } - - @TruffleBoundary - public static BigInt addZonedDateTime(JSContext ctx, JSRealm realm, BigInt epochNanoseconds, - TimeZoneMethodsRecord timeZoneRec, CalendarMethodsRecord calendarRec, - long years, long months, long weeks, long days, - long hours, long minutes, long seconds, long milliseconds, long microseconds, BigInteger nanoseconds, - JSTemporalPlainDateTimeObject precalculatedPlainDateTime, JSDynamicObject options) { - if (years == 0 && months == 0 && weeks == 0 && days == 0) { - return addInstant(epochNanoseconds, hours, minutes, seconds, milliseconds, microseconds, nanoseconds); - } - JSTemporalInstantObject instant = JSTemporalInstant.create(ctx, realm, epochNanoseconds); - JSTemporalPlainDateTimeObject temporalDateTime = precalculatedPlainDateTime != null - ? precalculatedPlainDateTime - : builtinTimeZoneGetPlainDateTimeFor(ctx, realm, timeZoneRec, instant, calendarRec.receiver()); - if (years == 0 && months == 0 && weeks == 0) { - Overflow overflow = toTemporalOverflow(options); - BigInt intermediate = addDaysToZonedDateTime(ctx, realm, instant, temporalDateTime, timeZoneRec, (int) days, overflow).epochNanoseconds(); - return addInstant(intermediate, hours, minutes, seconds, milliseconds, microseconds, nanoseconds); - } - JSTemporalPlainDateObject datePart = JSTemporalPlainDate.create(ctx, realm, temporalDateTime.getYear(), temporalDateTime.getMonth(), temporalDateTime.getDay(), - calendarRec.receiver(), null, InlinedBranchProfile.getUncached()); - JSTemporalDurationObject dateDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, years, months, weeks, days, 0, 0, 0, 0, 0, 0, null, InlinedBranchProfile.getUncached()); - JSTemporalPlainDateObject addedDate = calendarDateAdd(calendarRec, datePart, dateDuration, options); - JSTemporalPlainDateTimeObject intermediateDateTime = JSTemporalPlainDateTime.create(ctx, realm, addedDate.getYear(), addedDate.getMonth(), addedDate.getDay(), - temporalDateTime.getHour(), temporalDateTime.getMinute(), temporalDateTime.getSecond(), - temporalDateTime.getMillisecond(), temporalDateTime.getMicrosecond(), temporalDateTime.getNanosecond(), calendarRec.receiver()); - JSTemporalInstantObject intermediateInstant = builtinTimeZoneGetInstantFor(ctx, realm, timeZoneRec, intermediateDateTime, Disambiguation.COMPATIBLE); - return addInstant(intermediateInstant.getNanoseconds(), hours, minutes, seconds, milliseconds, microseconds, nanoseconds); - } - - @TruffleBoundary - public static BigInt addZonedDateTime(JSContext ctx, JSRealm realm, BigInt epochNanoseconds, - TimeZoneMethodsRecord timeZoneRec, CalendarMethodsRecord calendarRec, - double years, double months, double weeks, double days, - BigInt norm, - JSTemporalPlainDateTimeObject precalculatedPlainDateTime) { - return addZonedDateTime(ctx, realm, epochNanoseconds, timeZoneRec, calendarRec, years, months, weeks, days, norm, - precalculatedPlainDateTime, Undefined.instance); - } - - @TruffleBoundary - public static BigInt addZonedDateTime(JSContext ctx, JSRealm realm, BigInt epochNanoseconds, - TimeZoneMethodsRecord timeZoneRec, CalendarMethodsRecord calendarRec, - double years, double months, double weeks, double days, - BigInt norm, - JSTemporalPlainDateTimeObject precalculatedPlainDateTime, JSDynamicObject options) { - if (years == 0 && months == 0 && weeks == 0 && days == 0) { - return addInstant(epochNanoseconds, norm); - } - JSTemporalInstantObject instant = JSTemporalInstant.create(ctx, realm, epochNanoseconds); - JSTemporalPlainDateTimeObject temporalDateTime = precalculatedPlainDateTime != null - ? precalculatedPlainDateTime - : builtinTimeZoneGetPlainDateTimeFor(ctx, realm, timeZoneRec, instant, calendarRec.receiver()); - if (years == 0 && months == 0 && weeks == 0) { - Overflow overflow = toTemporalOverflow(options); - BigInt intermediate = addDaysToZonedDateTime(ctx, realm, instant, temporalDateTime, timeZoneRec, (int) days, overflow).epochNanoseconds(); - return addInstant(intermediate, norm); - } - JSTemporalPlainDateObject datePart = JSTemporalPlainDate.create(ctx, realm, temporalDateTime.getYear(), temporalDateTime.getMonth(), temporalDateTime.getDay(), - calendarRec.receiver(), null, InlinedBranchProfile.getUncached()); - JSTemporalDurationObject dateDuration = JSTemporalDuration.createTemporalDuration(ctx, realm, years, months, weeks, days, 0, 0, 0, 0, 0, 0, null, InlinedBranchProfile.getUncached()); - JSTemporalPlainDateObject addedDate = calendarDateAdd(calendarRec, datePart, dateDuration, options); - JSTemporalPlainDateTimeObject intermediateDateTime = JSTemporalPlainDateTime.create(ctx, realm, addedDate.getYear(), addedDate.getMonth(), addedDate.getDay(), - temporalDateTime.getHour(), temporalDateTime.getMinute(), temporalDateTime.getSecond(), - temporalDateTime.getMillisecond(), temporalDateTime.getMicrosecond(), temporalDateTime.getNanosecond(), calendarRec.receiver()); - JSTemporalInstantObject intermediateInstant = builtinTimeZoneGetInstantFor(ctx, realm, timeZoneRec, intermediateDateTime, Disambiguation.COMPATIBLE); - return addInstant(intermediateInstant.getNanoseconds(), norm); - } - public static boolean timeZoneEquals(Object tz1, Object tz2, ToTemporalTimeZoneIdentifierNode toTimeZoneIdentifier) { if (tz1 == tz2) { return true; From 64b2ed60204525e9ae5e6ae9925ddd527d4468c7 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 10 Jun 2024 15:29:27 +0200 Subject: [PATCH 029/265] Move ISODateToEpochDays to JSDate and share implementation with MakeDay. --- .../TemporalCalendarPrototypeBuiltins.java | 3 +- .../truffle/js/runtime/builtins/JSDate.java | 28 +++++++++++---- .../truffle/js/runtime/util/TemporalUtil.java | 35 ++++--------------- 3 files changed, 30 insertions(+), 36 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalCalendarPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalCalendarPrototypeBuiltins.java index b4138be6b5b..7329531c652 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalCalendarPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalCalendarPrototypeBuiltins.java @@ -97,6 +97,7 @@ import com.oracle.truffle.js.runtime.JSRealm; import com.oracle.truffle.js.runtime.JSRuntime; import com.oracle.truffle.js.runtime.builtins.BuiltinEnum; +import com.oracle.truffle.js.runtime.builtins.JSDate; import com.oracle.truffle.js.runtime.builtins.temporal.ISODateRecord; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalCalendar; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalCalendarObject; @@ -848,7 +849,7 @@ protected boolean inLeapYear(JSTemporalCalendarObject calendar, Object temporalD JSTemporalPlainDateObject dateLike = toTemporalDate.execute(temporalDateLike); year = dateLike.getYear(); } - return TemporalUtil.isISOLeapYear(year); + return JSDate.isLeapYear(year); } @SuppressWarnings("unused") diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSDate.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSDate.java index 4c5c1049efd..0800ba60349 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSDate.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSDate.java @@ -43,7 +43,6 @@ import java.time.Instant; import java.time.LocalDate; import java.time.LocalTime; -import java.time.ZoneOffset; import org.graalvm.shadowed.com.ibm.icu.impl.Grego; import org.graalvm.shadowed.com.ibm.icu.text.DateFormat; @@ -87,6 +86,7 @@ public final class JSDate extends JSNonProxy implements JSConstructorFactory.Def // slightly beyond MAX_DATE (+/- 273,790 years) // cf. https://tc39.es/ecma262/#sec-time-values-and-time-range public static final double MAX_YEAR_VALUE = 300000; + public static final double MIN_YEAR_VALUE = -300000; private static final int DAYS_IN_4_YEARS = 4 * 365 + 1; private static final int DAYS_IN_100_YEARS = 25 * DAYS_IN_4_YEARS - 1; @@ -207,7 +207,7 @@ public static int yearFromDays(int daysAfter1970) { // days after year (2000 - yearShift) int days = daysAfter2000 + DAY_SHIFT; // we need days > 0 to ensure that integer division rounds correctly - assert days > 0; + assert days > 0 : days; int year = 400 * (days / DAYS_IN_400_YEARS); int remainingDays = days % DAYS_IN_400_YEARS; @@ -223,7 +223,7 @@ public static int yearFromDays(int daysAfter1970) { return year - YEAR_SHIFT + 2000; } - private static boolean isLeapYear(int year) { + public static boolean isLeapYear(int year) { if (year % 4 != 0) { return false; } @@ -246,7 +246,7 @@ public static int monthFromTime(double dt) { } private static int monthFromTimeIntl(boolean leapYear, int day) { - assert (0 <= day) && (day < (365 + (leapYear ? 1 : 0))) : "should not reach here"; + assert (0 <= day) && (day < (365 + (leapYear ? 1 : 0))) : day; if (day < 31) { return 0; @@ -497,12 +497,26 @@ public static double makeDay(double year, double month, double date) { mn += 12; } - if (ym < -MAX_YEAR_VALUE || ym > MAX_YEAR_VALUE) { + if (ym < MIN_YEAR_VALUE || ym > MAX_YEAR_VALUE) { return Double.NaN; } - double t = LocalDate.of((int) ym, mn + 1, 1).atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli(); - return day(t) + dt - 1; + return isoDateToEpochDaysResolvedYM((int) ym, mn + 1, 1) + dt - 1; + } + + @TruffleBoundary + public static long isoDateToEpochDays(int year, int month, int date) { + int resolvedYear = year + month / 12; + int resolvedMonth = month % 12; + if (resolvedMonth < 0) { + resolvedMonth += 12; + } + return isoDateToEpochDaysResolvedYM(resolvedYear, resolvedMonth + 1, date); + } + + @TruffleBoundary + private static long isoDateToEpochDaysResolvedYM(int y, int m, int date) { + return LocalDate.of(y, m, 1).toEpochDay() + date - 1; } // 15.9.1.13 diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java index e58a57d65e6..713bc90fae2 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java @@ -97,7 +97,6 @@ import java.math.BigInteger; import java.math.MathContext; import java.time.Instant; -import java.time.LocalDate; import java.time.Year; import java.time.ZoneId; import java.time.ZoneOffset; @@ -1078,7 +1077,7 @@ public static long weekOfToISOWeekOfYear(int year, int month, int day) { long week = Math.floorDiv(dayOfYear + daysInWeek - dayOfWeek + wednesday, daysInWeek); if (week < 1) { long dayOfJan1st = toISODayOfWeek(year, 1, 1); - if (dayOfJan1st == friday || (dayOfJan1st == saturday && isISOLeapYear(year - 1))) { + if (dayOfJan1st == friday || (dayOfJan1st == saturday && JSDate.isLeapYear(year - 1))) { return maxWeekNumber; } else { return maxWeekNumber - 1; @@ -1122,12 +1121,8 @@ public static long yearOfToISOWeekOfYear(int year, int month, int day) { return year; } - public static boolean isISOLeapYear(int year) { - return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)); - } - public static int isoDaysInYear(int year) { - if (isISOLeapYear(year)) { + if (JSDate.isLeapYear(year)) { return 366; } return 365; @@ -1141,7 +1136,7 @@ public static int isoDaysInMonth(int year, int month) { if (month == 4 || month == 6 || month == 9 || month == 11) { return 30; } - if (isISOLeapYear(year)) { + if (JSDate.isLeapYear(year)) { return 29; } return 28; @@ -1307,7 +1302,7 @@ public static BigInt getUTCEpochNanoseconds(int year, int month, int day, int ho assert isValidTime(hour, minute, second, millisecond, microsecond, nanosecond); // 1. Let date be MakeDay(year, month - 1, day). - long date = isoDateToEpochDays(year, month - 1, day); + long date = JSDate.isoDateToEpochDays(year, month - 1, day); // 2. Let time be MakeTime(hour, minute, second, millisecond). long time = hour * JSDate.MS_PER_HOUR + minute * JSDate.MS_PER_MINUTE + second * JSDate.MS_PER_SECOND + millisecond; // 3. Let ms be MakeDate(date, time). @@ -1509,22 +1504,6 @@ public static ISODateRecord regulateISODate(int year, int monthParam, int dayPar return new ISODateRecord(year, month, day); } - /** - * Corresponds to {@link JSDate#makeDay MakeDay}. - */ - @TruffleBoundary - public static long isoDateToEpochDays(int year, int month, int date) { - int resolvedYear = year + month / 12; - int resolvedMonth = month % 12; - if (resolvedMonth < 0) { - resolvedMonth += 12; - } - // Year must be in the supported range for LocalDate. - assert resolvedYear >= Year.MIN_VALUE && resolvedYear <= Year.MAX_VALUE : resolvedYear; - long t = LocalDate.of(resolvedYear, resolvedMonth + 1, 1).atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli(); - return Math.floorDiv(t, JSDate.MS_PER_DAY) + date - 1; - } - @TruffleBoundary public static ISODateRecord balanceISODate(int year, int month, int day) { if (year < -1000000 || 1000000 < year || day < -ISO_DATE_MAX_UTC_OFFSET_DAYS || ISO_DATE_MAX_UTC_OFFSET_DAYS < day) { @@ -1533,7 +1512,7 @@ public static ISODateRecord balanceISODate(int year, int month, int day) { // This is OK since all callers would throw a RangeError immediately after anyway. throw Errors.createRangeError("Date outside of supported range"); } - long epochDays = isoDateToEpochDays(year, month - 1, day); + long epochDays = JSDate.isoDateToEpochDays(year, month - 1, day); long ms = epochDays * JSDate.MS_PER_DAY; return createISODateRecord(JSDate.yearFromTime(ms), JSDate.monthFromTime(ms) + 1, JSDate.dateFromTime(ms)); } @@ -2332,8 +2311,8 @@ public static BigInt zeroTimeDuration() { @TruffleBoundary public static long daysUntil(JSTemporalPlainDateObject earlier, JSTemporalPlainDateObject later) { - long epochDays1 = isoDateToEpochDays(earlier.getYear(), earlier.getMonth() - 1, earlier.getDay()); - long epochDays2 = isoDateToEpochDays(later.getYear(), later.getMonth() - 1, later.getDay()); + long epochDays1 = JSDate.isoDateToEpochDays(earlier.getYear(), earlier.getMonth() - 1, earlier.getDay()); + long epochDays2 = JSDate.isoDateToEpochDays(later.getYear(), later.getMonth() - 1, later.getDay()); return epochDays2 - epochDays1; } From c8664d88e2b378a1f8d52320e1a1896a6cb53c43 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 10 Jun 2024 16:29:02 +0200 Subject: [PATCH 030/265] Use JS BigInt consistently instead of java.math.BigInteger. --- .../TemporalInstantFunctionBuiltins.java | 21 ++-- .../TemporalInstantPrototypeBuiltins.java | 9 +- .../builtins/temporal/JSTemporalDuration.java | 44 +++---- .../temporal/JSTemporalInstantObject.java | 3 +- .../JSTemporalZonedDateTimeObject.java | 3 +- .../truffle/js/runtime/util/TemporalUtil.java | 115 +++++++++--------- 6 files changed, 93 insertions(+), 102 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalInstantFunctionBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalInstantFunctionBuiltins.java index 8d271a0814b..e2e034d05b6 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalInstantFunctionBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalInstantFunctionBuiltins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -40,8 +40,6 @@ */ package com.oracle.truffle.js.builtins.temporal; -import java.math.BigInteger; - import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.js.builtins.JSBuiltinsContainer; @@ -54,7 +52,6 @@ import com.oracle.truffle.js.nodes.function.JSBuiltinNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalInstantNode; import com.oracle.truffle.js.runtime.BigInt; -import com.oracle.truffle.js.runtime.Boundaries; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRuntime; import com.oracle.truffle.js.runtime.builtins.BuiltinEnum; @@ -97,13 +94,13 @@ protected Object createNode(JSContext context, JSBuiltin builtin, boolean constr case from: return JSTemporalInstantFromNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context)); case fromEpochSeconds: - return JSTemporalInstantFromEpochNodeGen.create(context, builtin, 1_000_000_000, true, args().fixedArgs(1).createArgumentNodes(context)); + return JSTemporalInstantFromEpochNodeGen.create(context, builtin, TemporalUtil.BI_NS_PER_SECOND, true, args().fixedArgs(1).createArgumentNodes(context)); case fromEpochMilliseconds: - return JSTemporalInstantFromEpochNodeGen.create(context, builtin, 1_000_000, true, args().fixedArgs(1).createArgumentNodes(context)); + return JSTemporalInstantFromEpochNodeGen.create(context, builtin, TemporalUtil.BI_NS_PER_MS, true, args().fixedArgs(1).createArgumentNodes(context)); case fromEpochMicroseconds: - return JSTemporalInstantFromEpochNodeGen.create(context, builtin, 1000, false, args().fixedArgs(1).createArgumentNodes(context)); + return JSTemporalInstantFromEpochNodeGen.create(context, builtin, TemporalUtil.BI_1000, false, args().fixedArgs(1).createArgumentNodes(context)); case fromEpochNanoseconds: - return JSTemporalInstantFromEpochNodeGen.create(context, builtin, 1, false, args().fixedArgs(1).createArgumentNodes(context)); + return JSTemporalInstantFromEpochNodeGen.create(context, builtin, BigInt.ONE, false, args().fixedArgs(1).createArgumentNodes(context)); case compare: return JSTemporalInstantCompareNodeGen.create(context, builtin, args().fixedArgs(2).createArgumentNodes(context)); } @@ -129,12 +126,12 @@ protected JSTemporalInstantObject from(Object item, public abstract static class JSTemporalInstantFromEpochNode extends JSBuiltinNode { - private final BigInteger factor; + private final BigInt factor; private final boolean numberToBigIntConversion; - public JSTemporalInstantFromEpochNode(JSContext context, JSBuiltin builtin, long factor, boolean numberToBigIntConversion) { + public JSTemporalInstantFromEpochNode(JSContext context, JSBuiltin builtin, BigInt factor, boolean numberToBigIntConversion) { super(context, builtin); - this.factor = BigInteger.valueOf(factor); + this.factor = factor; this.numberToBigIntConversion = numberToBigIntConversion; } @@ -149,7 +146,7 @@ protected JSTemporalInstantObject from(Object epochParam, } else { epochNanoseconds = JSRuntime.toBigInt(epochParam); } - epochNanoseconds = new BigInt(Boundaries.bigIntegerMultiply(epochNanoseconds.bigIntegerValue(), factor)); + epochNanoseconds = epochNanoseconds.multiply(factor); if (!TemporalUtil.isValidEpochNanoseconds(epochNanoseconds)) { throw TemporalErrors.createRangeErrorInvalidNanoseconds(); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalInstantPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalInstantPrototypeBuiltins.java index 72183342da0..ac9ed01bd65 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalInstantPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalInstantPrototypeBuiltins.java @@ -45,7 +45,6 @@ import static com.oracle.truffle.js.runtime.util.TemporalConstants.TIME_ZONE; import static com.oracle.truffle.js.runtime.util.TemporalConstants.TRUNC; -import java.math.BigInteger; import java.util.EnumSet; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -199,15 +198,15 @@ protected JSTemporalInstantGetterNode(JSContext context, JSBuiltin builtin, Temp @TruffleBoundary @Specialization protected Object instantGetter(JSTemporalInstantObject instant) { - BigInteger ns = instant.getNanoseconds().bigIntegerValue(); + BigInt ns = instant.getNanoseconds(); switch (property) { // roundTowardsZero is a no-op for BigIntegers case epochSeconds: - return ns.divide(TemporalUtil.BI_10_POW_9).doubleValue(); + return ns.divide(TemporalUtil.BI_NS_PER_SECOND).doubleValue(); case epochMilliseconds: - return ns.divide(TemporalUtil.BI_10_POW_6).doubleValue(); + return ns.divide(TemporalUtil.BI_NS_PER_MS).doubleValue(); case epochMicroseconds: - return new BigInt(ns.divide(TemporalUtil.BI_1000)); + return ns.divide(TemporalUtil.BI_1000); case epochNanoseconds: return instant.getNanoseconds(); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalDuration.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalDuration.java index 281163218b0..36e7d9b6247 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalDuration.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalDuration.java @@ -44,7 +44,6 @@ import static com.oracle.truffle.js.runtime.util.TemporalUtil.bitoi; import java.math.BigDecimal; -import java.math.BigInteger; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -57,6 +56,7 @@ import com.oracle.truffle.js.builtins.temporal.TemporalDurationFunctionBuiltins; import com.oracle.truffle.js.builtins.temporal.TemporalDurationPrototypeBuiltins; import com.oracle.truffle.js.nodes.cast.JSNumberToBigIntNode; +import com.oracle.truffle.js.runtime.BigInt; import com.oracle.truffle.js.runtime.Errors; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRealm; @@ -339,17 +339,17 @@ public static TruffleString temporalDurationToString(double yearsP, double month double microsecondsP, double nanosecondsP, Object precision, JSNumberToBigIntNode toBigIntNode) { int sign = TemporalUtil.durationSign(yearsP, monthsP, weeksP, daysP, hoursP, minutesP, secondsP, millisecondsP, microsecondsP, nanosecondsP); - BigInteger nanosecondsBI = toBigInteger(nanosecondsP, toBigIntNode); - BigInteger microsecondsBI = toBigInteger(microsecondsP, toBigIntNode); - BigInteger millisecondsBI = toBigInteger(millisecondsP, toBigIntNode); - BigInteger secondsBI = toBigInteger(secondsP, toBigIntNode); + BigInt nanosecondsBI = toBigInteger(nanosecondsP, toBigIntNode); + BigInt microsecondsBI = toBigInteger(microsecondsP, toBigIntNode); + BigInt millisecondsBI = toBigInteger(millisecondsP, toBigIntNode); + BigInt secondsBI = toBigInteger(secondsP, toBigIntNode); - BigInteger yearsBI = toBigIntegerOrNull(Math.abs(yearsP), toBigIntNode); - BigInteger monthsBI = toBigIntegerOrNull(Math.abs(monthsP), toBigIntNode); - BigInteger weeksBI = toBigIntegerOrNull(Math.abs(weeksP), toBigIntNode); - BigInteger daysBI = toBigIntegerOrNull(Math.abs(daysP), toBigIntNode); - BigInteger hoursBI = toBigIntegerOrNull(Math.abs(hoursP), toBigIntNode); - BigInteger minutesBI = toBigIntegerOrNull(Math.abs(minutesP), toBigIntNode); + BigInt yearsBI = toBigIntegerOrNull(Math.abs(yearsP), toBigIntNode); + BigInt monthsBI = toBigIntegerOrNull(Math.abs(monthsP), toBigIntNode); + BigInt weeksBI = toBigIntegerOrNull(Math.abs(weeksP), toBigIntNode); + BigInt daysBI = toBigIntegerOrNull(Math.abs(daysP), toBigIntNode); + BigInt hoursBI = toBigIntegerOrNull(Math.abs(hoursP), toBigIntNode); + BigInt minutesBI = toBigIntegerOrNull(Math.abs(minutesP), toBigIntNode); boolean condition = secondsP != 0 || millisecondsP != 0 || microsecondsP != 0 || nanosecondsP != 0 || (yearsP == 0 && monthsP == 0 && weeksP == 0 && daysP == 0 && hoursP == 0 && minutesP == 0); @@ -357,18 +357,18 @@ public static TruffleString temporalDurationToString(double yearsP, double month } @TruffleBoundary - private static TruffleString temporalDurationToStringIntl(BigInteger yearsP, BigInteger monthsP, BigInteger weeksP, BigInteger daysP, BigInteger hoursP, BigInteger minutesP, BigInteger secondsP, - BigInteger millisecondsP, BigInteger microsecondsP, BigInteger nanosecondsP, Object precision, int sign, boolean condition) { - BigInteger[] res = nanosecondsP.divideAndRemainder(TemporalUtil.BI_1000); - BigInteger microseconds = microsecondsP.add(res[0]); - BigInteger nanoseconds = res[1]; + private static TruffleString temporalDurationToStringIntl(BigInt yearsP, BigInt monthsP, BigInt weeksP, BigInt daysP, BigInt hoursP, BigInt minutesP, BigInt secondsP, + BigInt millisecondsP, BigInt microsecondsP, BigInt nanosecondsP, Object precision, int sign, boolean condition) { + BigInt[] res = nanosecondsP.divideAndRemainder(TemporalUtil.BI_1000); + BigInt microseconds = microsecondsP.add(res[0]); + BigInt nanoseconds = res[1]; res = microseconds.divideAndRemainder(TemporalUtil.BI_1000); - BigInteger milliseconds = millisecondsP.add(res[0]); + BigInt milliseconds = millisecondsP.add(res[0]); microseconds = res[1]; res = milliseconds.divideAndRemainder(TemporalUtil.BI_1000); - BigInteger seconds = secondsP.add(res[0]); + BigInt seconds = secondsP.add(res[0]); milliseconds = res[1]; StringBuilder datePart = new StringBuilder(); @@ -436,12 +436,12 @@ private static TruffleString temporalDurationToStringIntl(BigInteger yearsP, Big return Strings.builderToString(result); } - private static BigInteger toBigIntegerOrNull(double value, JSNumberToBigIntNode toBigIntNode) { - return (value != 0) ? toBigIntNode.executeBigInt(value).bigIntegerValue() : null; + private static BigInt toBigIntegerOrNull(double value, JSNumberToBigIntNode toBigIntNode) { + return (value != 0) ? toBigIntNode.executeBigInt(value) : null; } - private static BigInteger toBigInteger(double value, JSNumberToBigIntNode toBigIntNode) { - return toBigIntNode.executeBigInt(value).bigIntegerValue(); + private static BigInt toBigInteger(double value, JSNumberToBigIntNode toBigIntNode) { + return toBigIntNode.executeBigInt(value); } // endregion } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalInstantObject.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalInstantObject.java index ca3a2e880ca..0ac3f24221d 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalInstantObject.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalInstantObject.java @@ -40,7 +40,6 @@ */ package com.oracle.truffle.js.runtime.builtins.temporal; -import java.math.BigInteger; import java.time.Instant; import java.time.LocalDate; import java.time.LocalTime; @@ -75,7 +74,7 @@ public BigInt getNanoseconds() { @ExportMessage @TruffleBoundary Instant asInstant() { - BigInteger[] res = nanoseconds.bigIntegerValue().divideAndRemainder(TemporalUtil.BI_10_POW_9); + BigInt[] res = nanoseconds.divideAndRemainder(TemporalUtil.BI_NS_PER_SECOND); return Instant.ofEpochSecond(res[0].longValue(), res[1].intValue()); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalZonedDateTimeObject.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalZonedDateTimeObject.java index 594139aa305..4fd2132c280 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalZonedDateTimeObject.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/temporal/JSTemporalZonedDateTimeObject.java @@ -40,7 +40,6 @@ */ package com.oracle.truffle.js.runtime.builtins.temporal; -import java.math.BigInteger; import java.time.DateTimeException; import java.time.Instant; import java.time.LocalDate; @@ -83,7 +82,7 @@ public Object getTimeZone() { @TruffleBoundary private Instant toInstant() { - BigInteger[] res = nanoseconds.bigIntegerValue().divideAndRemainder(TemporalUtil.BI_10_POW_9); + BigInt[] res = nanoseconds.divideAndRemainder(TemporalUtil.BI_NS_PER_SECOND); return Instant.ofEpochSecond(res[0].longValue(), res[1].intValue()); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java index 713bc90fae2..80e71eb071f 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java @@ -94,7 +94,6 @@ import static com.oracle.truffle.js.runtime.util.TemporalConstants.YEARS; import java.math.BigDecimal; -import java.math.BigInteger; import java.math.MathContext; import java.time.Instant; import java.time.Year; @@ -296,13 +295,13 @@ public final class TemporalUtil { /** maxTimeDuration = 2**53 * 10**9 - 1 = 9,007,199,254,740,991,999,999,999. */ private static final BigInt MAX_TIME_DURATION = BigInt.valueOf(1L << 53).multiply(BigInt.valueOf(1_000_000_000L)).subtract(BigInt.ONE); - public static final BigInteger BI_36_10_POW_11 = BigInteger.valueOf(3600000000000L); - public static final BigInteger BI_6_10_POW_10 = BigInteger.valueOf(60000000000L); - public static final BigInteger BI_10_POW_9 = BigInteger.valueOf(1000000000); // 10 ^ 9 - public static final BigInteger BI_10_POW_6 = BigInteger.valueOf(1000000); // 10 ^ 6 - public static final BigInteger BI_1000 = BigInteger.valueOf(1000); // 10 ^ 3 - public static final BigInteger BI_24 = BigInteger.valueOf(24); - public static final BigInteger BI_60 = BigInteger.valueOf(60); + public static final BigInt BI_NS_PER_HOUR = BigInt.valueOf(3_600_000_000_000L); + public static final BigInt BI_NS_PER_MINUTE = BigInt.valueOf(60_000_000_000L); + public static final BigInt BI_NS_PER_SECOND = BigInt.valueOf(1_000_000_000); + public static final BigInt BI_NS_PER_MS = BigInt.valueOf(1_000_000); + public static final BigInt BI_1000 = BigInt.valueOf(1_000); + public static final BigInt BI_24 = BigInt.valueOf(24); + public static final BigInt BI_60 = BigInt.valueOf(60); public static final BigDecimal BD_10 = BigDecimal.valueOf(10); public static final BigDecimal BD_60 = BigDecimal.valueOf(60); @@ -1306,11 +1305,11 @@ public static BigInt getUTCEpochNanoseconds(int year, int month, int day, int ho // 2. Let time be MakeTime(hour, minute, second, millisecond). long time = hour * JSDate.MS_PER_HOUR + minute * JSDate.MS_PER_MINUTE + second * JSDate.MS_PER_SECOND + millisecond; // 3. Let ms be MakeDate(date, time). - BigInteger ms = BigInteger.valueOf(date).multiply(BigInteger.valueOf(JSDate.MS_PER_DAY)).add(BigInteger.valueOf(time)); + BigInt ms = BigInt.valueOf(date).multiply(BigInt.valueOf(JSDate.MS_PER_DAY)).add(BigInt.valueOf(time)); // Let epochNanoseconds be ms * 1e6 + microsecond * 1e3 + nanosecond. - BigInteger epochNanoseconds = ms.multiply(BI_10_POW_6).add(BigInteger.valueOf(microsecond * 1000)).add(BigInteger.valueOf(nanosecond)); - return BigInt.fromBigInteger(epochNanoseconds); + BigInt epochNanoseconds = ms.multiply(BI_NS_PER_MS).add(BigInt.valueOf(microsecond * 1000)).add(BigInt.valueOf(nanosecond)); + return epochNanoseconds; } @TruffleBoundary @@ -1469,23 +1468,22 @@ public static JSTemporalDurationObject calendarDateUntil(CalendarMethodsRecord c public static BigInt roundTemporalInstant(BigInt ns, int increment, Unit unit, RoundingMode roundingMode) { BigInt incrementNs = BigInt.valueOf(increment); if (Unit.HOUR == unit) { - incrementNs = incrementNs.multiply(BigInt.valueOf(3_600_000_000_000L)); + incrementNs = incrementNs.multiply(BI_NS_PER_HOUR); } else if (Unit.MINUTE == unit) { - incrementNs = incrementNs.multiply(BigInt.valueOf(60_000_000_000L)); + incrementNs = incrementNs.multiply(BI_NS_PER_MINUTE); } else if (Unit.SECOND == unit) { - incrementNs = incrementNs.multiply(BigInt.valueOf(1_000_000_000L)); + incrementNs = incrementNs.multiply(BI_NS_PER_SECOND); } else if (Unit.MILLISECOND == unit) { - incrementNs = incrementNs.multiply(BigInt.valueOf(1_000_000L)); + incrementNs = incrementNs.multiply(BI_NS_PER_MS); } else if (Unit.MICROSECOND == unit) { - incrementNs = incrementNs.multiply(BigInt.valueOf(1_000L)); + incrementNs = incrementNs.multiply(BI_1000); } else { assert Unit.NANOSECOND == unit : unit; if (incrementNs.compareTo(BigInt.ONE) == 0) { return ns; } } - var x = ns; - return roundNumberToIncrementAsIfPositive(x, incrementNs, roundingMode); + return roundNumberToIncrementAsIfPositive(ns, incrementNs, roundingMode); } public static ISODateRecord regulateISODate(int year, int monthParam, int dayParam, Overflow overflow) { @@ -1936,14 +1934,14 @@ public static void rejectDurationSign(double years, double months, double weeks, @TruffleBoundary public static TimeDurationRecord balanceTimeDuration(BigInt normalizedTimeDuration, Unit largestUnit) { - BigInteger d = BigInteger.ZERO; - BigInteger h = BigInteger.ZERO; - BigInteger min = BigInteger.ZERO; - BigInteger s = BigInteger.ZERO; - BigInteger ms = BigInteger.ZERO; - BigInteger us = BigInteger.ZERO; + BigInt d = BigInt.ZERO; + BigInt h = BigInt.ZERO; + BigInt min = BigInt.ZERO; + BigInt s = BigInt.ZERO; + BigInt ms = BigInt.ZERO; + BigInt us = BigInt.ZERO; double sign = normalizedTimeDurationSign(normalizedTimeDuration); - BigInteger ns = normalizedTimeDurationAbs(normalizedTimeDuration).bigIntegerValue(); + BigInt ns = normalizedTimeDurationAbs(normalizedTimeDuration); switch (largestUnit) { case YEAR, MONTH, WEEK, DAY -> { var qr = ns.divideAndRemainder(BI_1000); @@ -2190,22 +2188,22 @@ public static AddDaysToZonedDateTimeResult addDaysToZonedDateTime(JSContext ctx, return new AddDaysToZonedDateTimeResult(instantResult.getNanoseconds(), instant, dateTimeResult); } - private static BigInteger dtobi(double d) { + private static BigInt dtobi(double d) { CompilerAsserts.neverPartOfCompilation(); - return new BigDecimal(d).toBigInteger(); + return BigInt.fromBigInteger(new BigDecimal(d).toBigInteger()); } @TruffleBoundary public static BigInt totalDurationNanoseconds(double days, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds) { - BigInteger d = dtobi(days).multiply(BI_24); - BigInteger h = dtobi(hours).add(d); - BigInteger min = dtobi(minutes).add(h.multiply(BI_60)); - BigInteger s = dtobi(seconds).add(min.multiply(BI_60)); - BigInteger ms = dtobi(milliseconds).add(s.multiply(BI_1000)); - BigInteger us = dtobi(microseconds).add(ms.multiply(BI_1000)); - BigInteger ns = dtobi(nanoseconds).add(us.multiply(BI_1000)); - return BigInt.fromBigInteger(ns); + BigInt d = dtobi(days).multiply(BI_24); + BigInt h = dtobi(hours).add(d); + BigInt min = dtobi(minutes).add(h.multiply(BI_60)); + BigInt s = dtobi(seconds).add(min.multiply(BI_60)); + BigInt ms = dtobi(milliseconds).add(s.multiply(BI_1000)); + BigInt us = dtobi(microseconds).add(ms.multiply(BI_1000)); + BigInt ns = dtobi(nanoseconds).add(us.multiply(BI_1000)); + return ns; } /** @@ -2218,19 +2216,19 @@ public static BigInt totalDurationNanoseconds(double days, double hours, double @TruffleBoundary public static BigInt normalizeTimeDuration(double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds) { - BigInteger h = dtobi(hours); - BigInteger min = dtobi(minutes).add(h.multiply(BI_60)); - BigInteger s = dtobi(seconds).add(min.multiply(BI_60)); - BigInteger ms = dtobi(milliseconds).add(s.multiply(BI_1000)); - BigInteger us = dtobi(microseconds).add(ms.multiply(BI_1000)); - BigInteger ns = dtobi(nanoseconds).add(us.multiply(BI_1000)); - return BigInt.fromBigInteger(ns); + BigInt h = dtobi(hours); + BigInt min = dtobi(minutes).add(h.multiply(BI_60)); + BigInt s = dtobi(seconds).add(min.multiply(BI_60)); + BigInt ms = dtobi(milliseconds).add(s.multiply(BI_1000)); + BigInt us = dtobi(microseconds).add(ms.multiply(BI_1000)); + BigInt ns = dtobi(nanoseconds).add(us.multiply(BI_1000)); + return ns; } @TruffleBoundary public static BigInt add24HourDaysToNormalizedTimeDuration(BigInt timeDurationTotalNanoseconds, double days) { assert JSRuntime.isIntegralNumber(days) : days; - BigInt result = timeDurationTotalNanoseconds.add(BigInt.fromBigInteger(dtobi(days)).multiply(BI_NS_PER_DAY)); + BigInt result = timeDurationTotalNanoseconds.add(dtobi(days).multiply(BI_NS_PER_DAY)); if (result.abs().compareTo(MAX_TIME_DURATION) > 0) { throw Errors.createRangeError("Time duration out of range"); } @@ -2289,12 +2287,12 @@ public static BigInt remainderNormalizedTimeDuration(BigInt normalizedTimeDurati @TruffleBoundary public static double normalizeTimeDurationSeconds(BigInt timeDurationTotalNanoseconds) { - return timeDurationTotalNanoseconds.bigIntegerValue().divide(BI_10_POW_9).doubleValue(); + return timeDurationTotalNanoseconds.divide(BI_NS_PER_SECOND).doubleValue(); } @TruffleBoundary public static double normalizeTimeDurationSubseconds(BigInt timeDurationTotalNanoseconds) { - return timeDurationTotalNanoseconds.bigIntegerValue().remainder(BI_10_POW_9).doubleValue(); + return timeDurationTotalNanoseconds.remainder(BI_NS_PER_SECOND).doubleValue(); } public static BigInt normalizedTimeDurationAbs(BigInt timeDurationTotalNanoseconds) { @@ -2510,7 +2508,7 @@ public static TimeRecord addTimeDouble(int hour, int minute, int second, int mil public static TimeRecord addTime(int hour, int minute, int second, int millisecond, int microsecond, double nanosecond, BigInt normalizedTimeDuration, Node node, InlinedBranchProfile errorBranch) { - BigInteger[] qr = normalizedTimeDuration.bigIntegerValue().divideAndRemainder(BI_10_POW_9); + BigInt[] qr = normalizedTimeDuration.divideAndRemainder(BI_NS_PER_SECOND); double seconds = second + qr[0].doubleValue(); // NormalizedTimeDurationSeconds double nanoseconds = nanosecond + qr[1].doubleValue(); // NormalizedTimeDurationSubseconds return balanceTimeDouble(hour, minute, seconds, millisecond, microsecond, nanoseconds, node, errorBranch); @@ -2607,7 +2605,7 @@ public static JSTemporalDateTimeRecord getISOPartsFromEpoch(BigInt epochNanoseco remainderNs = epochNanoseconds.longValue() % 1_000_000; epochMilliseconds = (epochNanoseconds.longValue() - remainderNs) / 1_000_000; } else { - BigInteger[] result = epochNanoseconds.bigIntegerValue().divideAndRemainder(BI_10_POW_6); + BigInt[] result = epochNanoseconds.divideAndRemainder(BI_NS_PER_MS); remainderNs = result[1].longValue(); epochMilliseconds = result[0].longValue(); } @@ -2701,18 +2699,17 @@ public static boolean isValidEpochNanoseconds(BigInt nanoseconds) { @TruffleBoundary public static BigInt addInstant(BigInt epochNanoseconds, double hours, double minutes, double seconds, double milliseconds, double microseconds, double nanoseconds) { - return addInstant(epochNanoseconds, dtol(hours), dtol(minutes), dtol(seconds), dtol(milliseconds), dtol(microseconds), BigInteger.valueOf(dtol(nanoseconds))); + return addInstant(epochNanoseconds, dtol(hours), dtol(minutes), dtol(seconds), dtol(milliseconds), dtol(microseconds), BigInt.valueOf(dtol(nanoseconds))); } @TruffleBoundary - public static BigInt addInstant(BigInt epochNanoseconds, long hours, long minutes, long seconds, long milliseconds, long microseconds, BigInteger nanoseconds) { - BigInteger res = epochNanoseconds.bigIntegerValue().add(nanoseconds); - res = res.add(BigInteger.valueOf(microseconds).multiply(BI_1000)); - res = res.add(BigInteger.valueOf(milliseconds).multiply(BI_10_POW_6)); - res = res.add(BigInteger.valueOf(seconds).multiply(BI_10_POW_9)); - res = res.add(BigInteger.valueOf(minutes).multiply(BI_6_10_POW_10)); - res = res.add(BigInteger.valueOf(hours).multiply(BI_36_10_POW_11)); - BigInt result = new BigInt(res); + public static BigInt addInstant(BigInt epochNanoseconds, long hours, long minutes, long seconds, long milliseconds, long microseconds, BigInt nanoseconds) { + BigInt result = epochNanoseconds.add(nanoseconds); + result = result.add(BigInt.valueOf(microseconds).multiply(BI_1000)); + result = result.add(BigInt.valueOf(milliseconds).multiply(BI_NS_PER_MS)); + result = result.add(BigInt.valueOf(seconds).multiply(BI_NS_PER_SECOND)); + result = result.add(BigInt.valueOf(minutes).multiply(BI_NS_PER_MINUTE)); + result = result.add(BigInt.valueOf(hours).multiply(BI_NS_PER_HOUR)); if (!isValidEpochNanoseconds(result)) { throw TemporalErrors.createRangeErrorInvalidNanoseconds(); } @@ -3252,7 +3249,7 @@ public static double getIANATimeZoneOffsetNanoseconds(BigInt nanoseconds, Truffl @TruffleBoundary public static OptionalLong getIANATimeZoneNextTransition(BigInt nanoseconds, TruffleString identifier) { try { - BigInteger[] sec = nanoseconds.bigIntegerValue().divideAndRemainder(BI_10_POW_9); + BigInt[] sec = nanoseconds.divideAndRemainder(BI_NS_PER_SECOND); Instant instant = Instant.ofEpochSecond(sec[0].longValue(), sec[1].longValue()); ZoneId zoneId = ZoneId.of(Strings.toJavaString(identifier)); ZoneRules zoneRule = zoneId.getRules(); @@ -3270,7 +3267,7 @@ public static OptionalLong getIANATimeZoneNextTransition(BigInt nanoseconds, Tru @TruffleBoundary public static OptionalLong getIANATimeZonePreviousTransition(BigInt nanoseconds, TruffleString identifier) { try { - BigInteger[] sec = nanoseconds.bigIntegerValue().divideAndRemainder(BI_10_POW_9); + BigInt[] sec = nanoseconds.divideAndRemainder(BI_NS_PER_SECOND); Instant instant = Instant.ofEpochSecond(sec[0].longValue(), sec[1].longValue()); ZoneId zoneId = ZoneId.of(Strings.toJavaString(identifier)); ZoneRules zoneRule = zoneId.getRules(); @@ -3469,7 +3466,7 @@ public static int ltoi(long l) { } @TruffleBoundary - public static int bitoi(BigInteger bi) { + public static int bitoi(BigInt bi) { double value = bi.doubleValue(); assert Double.isFinite(value); assert JSRuntime.doubleIsRepresentableAsInt(value); From 66f8fcdd91a38687b1f6f945110b4f0704788c27 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Mon, 10 Jun 2024 13:51:56 +0200 Subject: [PATCH 031/265] Removing the usages of the deprecated NodeCost. --- .../js/nodes/access/ArrayLiteralNode.java | 7 +----- .../FrequencyBasedPolymorphicAccessNode.java | 9 ++++---- .../js/nodes/access/GlobalObjectNode.java | 5 +--- .../js/nodes/access/GlobalScopeNode.java | 3 --- .../js/nodes/access/HasPropertyCacheNode.java | 3 --- .../js/nodes/access/JSProxyCallNode.java | 5 +--- .../nodes/access/JSProxyHasPropertyNode.java | 5 +--- .../nodes/access/JSProxyPropertyGetNode.java | 3 --- .../nodes/access/JSProxyPropertySetNode.java | 3 --- .../js/nodes/access/PropertyCacheNode.java | 23 ------------------- .../js/nodes/access/PropertyGetNode.java | 3 --- .../js/nodes/access/PropertySetNode.java | 3 --- .../js/nodes/access/ScopeFrameNode.java | 6 +---- .../truffle/js/nodes/binary/DualNode.java | 5 +--- .../js/nodes/control/AbstractBlockNode.java | 3 --- .../js/nodes/control/DiscardResultNode.java | 3 --- .../truffle/js/nodes/control/EmptyNode.java | 5 +--- .../js/nodes/function/FunctionBodyNode.java | 5 +--- .../js/nodes/function/FunctionRootNode.java | 5 ++-- .../js/nodes/function/JSFunctionCallNode.java | 18 --------------- .../truffle/js/nodes/unary/VoidNode.java | 5 ++-- .../js/runtime/JavaScriptRootNode.java | 5 ++-- 22 files changed, 18 insertions(+), 114 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ArrayLiteralNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ArrayLiteralNode.java index 0755e32c497..7d642dfbd06 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ArrayLiteralNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ArrayLiteralNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -53,8 +53,6 @@ import com.oracle.truffle.api.instrumentation.Tag; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.NodeCost; -import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.nodes.UnexpectedResultException; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -402,7 +400,6 @@ private JSArrayObject executeFallback(VirtualFrame frame, Object[] objectArray, } } - @NodeInfo(cost = NodeCost.MONOMORPHIC) private static class DefaultArrayLiteralNode extends DefaultArrayLiteralBaseNode { @Children protected final JavaScriptNode[] elements; @@ -428,7 +425,6 @@ protected JavaScriptNode getElement(int index) { } } - @NodeInfo(cost = NodeCost.MONOMORPHIC) private static class DefaultArrayLiteralOneElementNode extends DefaultArrayLiteralBaseNode { @Child protected JavaScriptNode child; @@ -455,7 +451,6 @@ protected JavaScriptNode getElement(int index) { } } - @NodeInfo(cost = NodeCost.MONOMORPHIC) private static final class DefaultObjectArrayWithEmptyLiteralNode extends DefaultArrayLiteralNode { DefaultObjectArrayWithEmptyLiteralNode(JSContext context, JavaScriptNode[] elements) { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/FrequencyBasedPolymorphicAccessNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/FrequencyBasedPolymorphicAccessNode.java index 8fb1506aa60..ab6af289ef5 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/FrequencyBasedPolymorphicAccessNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/FrequencyBasedPolymorphicAccessNode.java @@ -50,7 +50,6 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.nodes.ExplodeLoop; -import com.oracle.truffle.api.nodes.NodeCost; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.nodes.JavaScriptBaseNode; import com.oracle.truffle.js.runtime.JSContext; @@ -230,8 +229,8 @@ private boolean compiledSet(JSDynamicObject target, Object key, Object value, Ob // subsequent slots must be null, too, since we fill in order and never remove. break; } - if (highFrequencyKey.getCost() == NodeCost.MEGAMORPHIC) { - // ignore megamorphic cache nodes, they're not useful and bloat the code + if (highFrequencyKey.getCacheNode() != null && highFrequencyKey.getCacheNode().isGeneric()) { + // ignore generic cache nodes, they're not useful and bloat the code continue; } if (JSRuntime.propertyKeyEquals(equalsNode, highFrequencyKey.getKey(), key)) { @@ -293,8 +292,8 @@ private Object readFromCaches(Object key, Object target, Object receiver, Truffl // subsequent slots must be null, too, since we fill in order and never remove. break; } - if (highFrequencyKey.getCost() == NodeCost.MEGAMORPHIC) { - // ignore megamorphic cache nodes, they're not useful and bloat the code + if (highFrequencyKey.getCacheNode() != null && highFrequencyKey.getCacheNode().isGeneric()) { + // ignore generic cache nodes, they're not useful and bloat the code continue; } if (JSRuntime.propertyKeyEquals(equalsNode, highFrequencyKey.getKey(), key)) { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/GlobalObjectNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/GlobalObjectNode.java index 58769c4e597..b686f6d3d05 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/GlobalObjectNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/GlobalObjectNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -44,14 +44,11 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.Tag; -import com.oracle.truffle.api.nodes.NodeCost; -import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.js.nodes.JavaScriptNode; import com.oracle.truffle.js.nodes.RepeatableNode; import com.oracle.truffle.js.nodes.instrumentation.JSTags; import com.oracle.truffle.js.runtime.objects.JSDynamicObject; -@NodeInfo(cost = NodeCost.NONE) public class GlobalObjectNode extends JavaScriptNode implements RepeatableNode { protected GlobalObjectNode() { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/GlobalScopeNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/GlobalScopeNode.java index cefde1f8fdd..7ea7d80a5aa 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/GlobalScopeNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/GlobalScopeNode.java @@ -47,8 +47,6 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.Tag; -import com.oracle.truffle.api.nodes.NodeCost; -import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.object.Property; import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.profiles.InlinedBranchProfile; @@ -59,7 +57,6 @@ import com.oracle.truffle.js.runtime.objects.Dead; import com.oracle.truffle.js.runtime.objects.JSDynamicObject; -@NodeInfo(cost = NodeCost.NONE) public class GlobalScopeNode extends JavaScriptNode { protected final JSContext context; diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/HasPropertyCacheNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/HasPropertyCacheNode.java index cbf62ee593b..c94e0400536 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/HasPropertyCacheNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/HasPropertyCacheNode.java @@ -45,8 +45,6 @@ import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.nodes.ExplodeLoop; -import com.oracle.truffle.api.nodes.NodeCost; -import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.object.Location; import com.oracle.truffle.api.object.Property; import com.oracle.truffle.api.object.Shape; @@ -276,7 +274,6 @@ protected boolean hasProperty(Object thisObj, HasPropertyCacheNode root) { } } - @NodeInfo(cost = NodeCost.MEGAMORPHIC) public static final class GenericHasPropertyCacheNode extends HasCacheNode { @Child private InteropLibrary interop; private final JSClassProfile jsclassProfile = JSClassProfile.create(); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/JSProxyCallNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/JSProxyCallNode.java index 120d4f910c7..3b773cde9e4 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/JSProxyCallNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/JSProxyCallNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -44,8 +44,6 @@ import com.oracle.truffle.api.dsl.Cached.Shared; import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.NodeCost; -import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.js.nodes.JavaScriptBaseNode; @@ -65,7 +63,6 @@ import com.oracle.truffle.js.runtime.objects.Null; import com.oracle.truffle.js.runtime.objects.Undefined; -@NodeInfo(cost = NodeCost.NONE) @ImportStatic({JSProxy.class, JSArguments.class}) public abstract class JSProxyCallNode extends JavaScriptBaseNode { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/JSProxyHasPropertyNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/JSProxyHasPropertyNode.java index 0287d350cd7..45660538927 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/JSProxyHasPropertyNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/JSProxyHasPropertyNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -46,8 +46,6 @@ import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.NodeCost; -import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.js.nodes.JavaScriptBaseNode; @@ -66,7 +64,6 @@ import com.oracle.truffle.js.runtime.objects.Null; import com.oracle.truffle.js.runtime.objects.Undefined; -@NodeInfo(cost = NodeCost.NONE) @ImportStatic({JSProxy.class}) public abstract class JSProxyHasPropertyNode extends JavaScriptBaseNode { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/JSProxyPropertyGetNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/JSProxyPropertyGetNode.java index 95df46cd64a..383393997f4 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/JSProxyPropertyGetNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/JSProxyPropertyGetNode.java @@ -44,8 +44,6 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.NodeCost; -import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.object.HiddenKey; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -67,7 +65,6 @@ import com.oracle.truffle.js.runtime.objects.Undefined; import com.oracle.truffle.js.runtime.util.JSClassProfile; -@NodeInfo(cost = NodeCost.NONE) public abstract class JSProxyPropertyGetNode extends JavaScriptBaseNode { @Child protected GetMethodNode trapGet; diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/JSProxyPropertySetNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/JSProxyPropertySetNode.java index 5079d7d6aae..29f64355187 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/JSProxyPropertySetNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/JSProxyPropertySetNode.java @@ -44,8 +44,6 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.dsl.Specialization; -import com.oracle.truffle.api.nodes.NodeCost; -import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.object.HiddenKey; import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.profiles.InlinedConditionProfile; @@ -68,7 +66,6 @@ import com.oracle.truffle.js.runtime.objects.Undefined; import com.oracle.truffle.js.runtime.util.JSClassProfile; -@NodeInfo(cost = NodeCost.NONE) public abstract class JSProxyPropertySetNode extends JavaScriptBaseNode { private final JSContext context; private final boolean isStrict; diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/PropertyCacheNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/PropertyCacheNode.java index 65335633dba..d0a18168fd5 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/PropertyCacheNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/PropertyCacheNode.java @@ -54,7 +54,6 @@ import com.oracle.truffle.api.TruffleOptions; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.NodeCost; import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.object.DynamicObjectLibrary; import com.oracle.truffle.api.object.HiddenKey; @@ -136,10 +135,6 @@ protected boolean isUnstable() { return false; } - @Override - public final NodeCost getCost() { - return NodeCost.NONE; - } } /** @@ -886,10 +881,6 @@ protected String debugString() { return null; } - @Override - public final NodeCost getCost() { - return NodeCost.NONE; - } } protected final Object key; @@ -1416,20 +1407,6 @@ public final JSContext getContext() { protected abstract void setPropertyAssumptionCheckEnabled(boolean value); - @Override - public NodeCost getCost() { - T cacheNode = getCacheNode(); - if (cacheNode == null) { - return NodeCost.UNINITIALIZED; - } else if (cacheNode.isGeneric()) { - return NodeCost.MEGAMORPHIC; - } else if (cacheNode.getNext() == null) { - return NodeCost.MONOMORPHIC; - } else { - return NodeCost.POLYMORPHIC; - } - } - protected static boolean isArrayLengthProperty(Property property) { return JSProperty.isProxy(property) && JSProperty.getConstantProxy(property) instanceof JSArray.ArrayLengthProxyProperty; } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/PropertyGetNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/PropertyGetNode.java index 637203edf64..52153df0936 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/PropertyGetNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/PropertyGetNode.java @@ -61,8 +61,6 @@ import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.NodeCost; -import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.nodes.UnexpectedResultException; import com.oracle.truffle.api.object.DynamicObjectLibrary; import com.oracle.truffle.api.object.HiddenKey; @@ -1267,7 +1265,6 @@ protected Object getValue(Object thisObj, Object receiver, Object defaultValue, } - @NodeInfo(cost = NodeCost.MEGAMORPHIC) public static final class GenericPropertyGetNode extends GetCacheNode { @Child private JSToObjectNode toObjectNode; @Child private ForeignPropertyGetNode foreignGetNode; diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/PropertySetNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/PropertySetNode.java index 5334c4a843e..8ac3a483faf 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/PropertySetNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/PropertySetNode.java @@ -53,8 +53,6 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.api.nodes.ExplodeLoop; -import com.oracle.truffle.api.nodes.NodeCost; -import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.object.DynamicObjectLibrary; import com.oracle.truffle.api.object.HiddenKey; import com.oracle.truffle.api.object.Location; @@ -800,7 +798,6 @@ protected boolean setValueInt(Object thisObj, int value, Object receiver, Proper } } - @NodeInfo(cost = NodeCost.MEGAMORPHIC) public static final class GenericPropertySetNode extends SetCacheNode { @Child private JSToObjectNode toObjectNode; @Child private ForeignPropertySetNode foreignSetNode; diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ScopeFrameNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ScopeFrameNode.java index ac69485b326..792a9b34164 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ScopeFrameNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ScopeFrameNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -44,8 +44,6 @@ import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.nodes.ExplodeLoop; -import com.oracle.truffle.api.nodes.NodeCost; -import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.js.nodes.JSFrameSlot; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.nodes.JavaScriptBaseNode; @@ -112,7 +110,6 @@ public final boolean isAdoptable() { return false; } - @NodeInfo(cost = NodeCost.NONE) private static final class CurrentFrameNode extends ScopeFrameNode { private static final ScopeFrameNode INSTANCE = new CurrentFrameNode(); @@ -130,7 +127,6 @@ public Frame executeFrame(Frame frame) { } } - @NodeInfo(cost = NodeCost.NONE) private static final class CurrentBlockScopeFrameNode extends ScopeFrameNode { private final int blockScopeSlot; diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/binary/DualNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/binary/DualNode.java index 7362d2d69bd..1df56d2c9a5 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/binary/DualNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/binary/DualNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -44,8 +44,6 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.Tag; -import com.oracle.truffle.api.nodes.NodeCost; -import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.nodes.UnexpectedResultException; import com.oracle.truffle.js.nodes.JSNodeUtil; import com.oracle.truffle.js.nodes.JavaScriptNode; @@ -56,7 +54,6 @@ import com.oracle.truffle.js.nodes.control.VoidBlockNode; import com.oracle.truffle.js.nodes.control.YieldException; -@NodeInfo(cost = NodeCost.NONE) public class DualNode extends JavaScriptNode implements SequenceNode, ResumableNode.WithIntState { @Child private JavaScriptNode left; diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/control/AbstractBlockNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/control/AbstractBlockNode.java index 6cb129a29e0..00717242bbe 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/control/AbstractBlockNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/control/AbstractBlockNode.java @@ -45,14 +45,11 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.nodes.BlockNode; -import com.oracle.truffle.api.nodes.NodeCost; -import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.js.nodes.JSNodeUtil; import com.oracle.truffle.js.nodes.JavaScriptNode; import com.oracle.truffle.js.nodes.access.JSConstantNode.JSConstantUndefinedNode; import com.oracle.truffle.js.nodes.binary.DualNode; -@NodeInfo(cost = NodeCost.NONE) public abstract class AbstractBlockNode extends StatementNode implements SequenceNode, BlockNode.ElementExecutor { @Child protected BlockNode block; diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/control/DiscardResultNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/control/DiscardResultNode.java index 07eacb505d0..edb1c076675 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/control/DiscardResultNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/control/DiscardResultNode.java @@ -44,14 +44,11 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.Tag; -import com.oracle.truffle.api.nodes.NodeCost; -import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.js.nodes.JavaScriptNode; import com.oracle.truffle.js.nodes.access.JSConstantNode; import com.oracle.truffle.js.nodes.unary.JSUnaryNode; import com.oracle.truffle.js.runtime.objects.Undefined; -@NodeInfo(cost = NodeCost.NONE) public class DiscardResultNode extends JSUnaryNode { protected DiscardResultNode(JavaScriptNode operand) { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/control/EmptyNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/control/EmptyNode.java index cf4bef969da..4afc176d176 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/control/EmptyNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/control/EmptyNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -44,8 +44,6 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.Tag; -import com.oracle.truffle.api.nodes.NodeCost; -import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.js.nodes.JavaScriptNode; import com.oracle.truffle.js.nodes.RepeatableNode; import com.oracle.truffle.js.runtime.objects.Undefined; @@ -53,7 +51,6 @@ /** * 12.3 Empty Statement. */ -@NodeInfo(cost = NodeCost.NONE) public final class EmptyNode extends StatementNode implements RepeatableNode { EmptyNode() { } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/function/FunctionBodyNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/function/FunctionBodyNode.java index 5f6b37fb977..96c99900d5f 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/function/FunctionBodyNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/function/FunctionBodyNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -46,13 +46,10 @@ import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.InstrumentableNode; import com.oracle.truffle.api.instrumentation.Tag; -import com.oracle.truffle.api.nodes.NodeCost; -import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.js.nodes.JavaScriptNode; import com.oracle.truffle.js.nodes.instrumentation.DeclareTagProvider; import com.oracle.truffle.js.nodes.instrumentation.JSTags.DeclareTag; -@NodeInfo(cost = NodeCost.NONE) public class FunctionBodyNode extends AbstractBodyNode { @Child private JavaScriptNode body; diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/function/FunctionRootNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/function/FunctionRootNode.java index 8ce4683ca23..4962dc4ed5b 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/function/FunctionRootNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/function/FunctionRootNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -47,7 +47,6 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.VirtualFrame; -import com.oracle.truffle.api.nodes.NodeCost; import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.api.strings.TruffleString; @@ -62,7 +61,7 @@ import com.oracle.truffle.js.runtime.builtins.JSFunctionData.Target; import com.oracle.truffle.js.runtime.objects.ScriptOrModule; -@NodeInfo(cost = NodeCost.NONE, language = "JavaScript", description = "The root node of all functions in JavaScript.") +@NodeInfo(language = "JavaScript", description = "The root node of all functions in JavaScript.") public final class FunctionRootNode extends AbstractFunctionRootNode implements FrameDescriptorProvider, JSFunctionData.CallTargetInitializer { @Child private JavaScriptNode body; diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/function/JSFunctionCallNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/function/JSFunctionCallNode.java index a9dc94c3793..24fa4afed85 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/function/JSFunctionCallNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/function/JSFunctionCallNode.java @@ -70,7 +70,6 @@ import com.oracle.truffle.api.nodes.ExplodeLoop; import com.oracle.truffle.api.nodes.IndirectCallNode; import com.oracle.truffle.api.nodes.Node; -import com.oracle.truffle.api.nodes.NodeCost; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ValueProfile; @@ -458,19 +457,6 @@ private T replaceCached(T newNode, AbstractCacheNo return newNode; } - @Override - public NodeCost getCost() { - if (cacheNode == null) { - return NodeCost.UNINITIALIZED; - } else if (isGeneric(cacheNode)) { - return NodeCost.MEGAMORPHIC; - } else if (cacheNode.nextNode != null) { - return NodeCost.POLYMORPHIC; - } else { - return NodeCost.MONOMORPHIC; - } - } - @Override public JavaScriptNode getTarget() { return null; @@ -1140,10 +1126,6 @@ protected AbstractCacheNode withNext(AbstractCacheNode newNext) { return copy; } - @Override - public final NodeCost getCost() { - return NodeCost.NONE; - } } private abstract static class JSFunctionCacheNode extends AbstractCacheNode { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/unary/VoidNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/unary/VoidNode.java index 4b1d7b5fa34..048d1f9bc9d 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/unary/VoidNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/unary/VoidNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -44,7 +44,6 @@ import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.instrumentation.Tag; -import com.oracle.truffle.api.nodes.NodeCost; import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.js.nodes.JavaScriptNode; import com.oracle.truffle.js.nodes.access.JSConstantNode; @@ -52,7 +51,7 @@ import com.oracle.truffle.js.nodes.instrumentation.JSTags.UnaryOperationTag; import com.oracle.truffle.js.runtime.objects.Undefined; -@NodeInfo(shortName = "void", cost = NodeCost.NONE) +@NodeInfo(shortName = "void") public abstract class VoidNode extends JSUnaryNode { protected VoidNode(JavaScriptNode operand) { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JavaScriptRootNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JavaScriptRootNode.java index 5863797e4cd..f9b08e25447 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JavaScriptRootNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JavaScriptRootNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -45,14 +45,13 @@ import com.oracle.truffle.api.TruffleStackTraceElement; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.FrameDescriptor; -import com.oracle.truffle.api.nodes.NodeCost; import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.js.lang.JavaScriptLanguage; import com.oracle.truffle.js.runtime.builtins.JSFunction; -@NodeInfo(cost = NodeCost.NONE, language = "JavaScript", description = "The root node of all functions in JavaScript.") +@NodeInfo(language = "JavaScript", description = "The root node of all functions in JavaScript.") public abstract class JavaScriptRootNode extends RootNode { private static final FrameDescriptor SHARED_EMPTY_FRAMEDESCRIPTOR = FrameDescriptor.newBuilder(0).build(); public static final FrameDescriptor MODULE_DUMMY_FRAMEDESCRIPTOR = FrameDescriptor.newBuilder(0).build(); From e1145fd4f34db75c2f1139c98aae90f8c69fa646 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 10 Jun 2024 16:30:55 +0200 Subject: [PATCH 032/265] Remove unused boundary methods. --- .../oracle/truffle/js/runtime/Boundaries.java | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Boundaries.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Boundaries.java index efff0218f79..76dd93680bf 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Boundaries.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Boundaries.java @@ -40,8 +40,6 @@ */ package com.oracle.truffle.js.runtime; -import java.math.BigDecimal; -import java.math.BigInteger; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; @@ -232,21 +230,6 @@ public static boolean setContains(Set set, Object element) { return set.contains(element); } - @TruffleBoundary - public static BigInteger bigIntegerValueOf(long l) { - return BigInteger.valueOf(l); - } - - @TruffleBoundary - public static BigDecimal bigDecimalValueOf(long l) { - return BigDecimal.valueOf(l); - } - - @TruffleBoundary - public static BigInteger bigIntegerMultiply(BigInteger a, BigInteger b) { - return a.multiply(b); - } - @TruffleBoundary public static void queueAdd(Queue queue, T request) { queue.add(request); From a006b637e22a5faa711c111d2bd591123fd9137c Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Mon, 10 Jun 2024 14:18:03 +0200 Subject: [PATCH 033/265] Do not override the deprecated no argument isCaptureFramesForTrace(). --- .../truffle/js/nodes/promise/PromiseReactionJobNode.java | 3 ++- .../src/com/oracle/truffle/js/runtime/JavaScriptRootNode.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/PromiseReactionJobNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/PromiseReactionJobNode.java index e1b3f8a9d84..c1dfbf96dcc 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/PromiseReactionJobNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/PromiseReactionJobNode.java @@ -51,6 +51,7 @@ import com.oracle.truffle.api.instrumentation.ProbeNode; import com.oracle.truffle.api.instrumentation.StandardTags; import com.oracle.truffle.api.instrumentation.Tag; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.HiddenKey; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.js.nodes.JavaScriptBaseNode; @@ -212,7 +213,7 @@ private TryCatchNode.GetErrorObjectNode getErrorObject() { } @Override - public boolean isCaptureFramesForTrace() { + public boolean isCaptureFramesForTrace(@SuppressWarnings("unused") Node currentNode) { return context.isOptionAsyncStackTraces(); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JavaScriptRootNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JavaScriptRootNode.java index f9b08e25447..b0757a0f7e7 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JavaScriptRootNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JavaScriptRootNode.java @@ -45,6 +45,7 @@ import com.oracle.truffle.api.TruffleStackTraceElement; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.FrameDescriptor; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.SourceSection; @@ -108,7 +109,7 @@ public boolean isResumption() { } @Override - public boolean isCaptureFramesForTrace() { + public boolean isCaptureFramesForTrace(@SuppressWarnings("unused") Node currentNode) { return isFunction() || isResumption(); } From fa008046c7f6c541e87dfdcc75d7d03665456db8 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Mon, 10 Jun 2024 15:26:44 +0200 Subject: [PATCH 034/265] Do not use the deprecated no argument isPolyglotEvalAllowed(). --- .../src/com/oracle/truffle/js/runtime/JSRealm.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java index 0817cdef6ea..d16ab76b719 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java @@ -2070,7 +2070,7 @@ public void setupGlobals() { JSObjectUtil.putDataProperty(getScriptEngineImportScope(), builtin, lookupFunction(GlobalBuiltins.GLOBAL_NASHORN_EXTENSIONS, builtin), JSAttributes.notConfigurableNotEnumerableNotWritable()); } - if (getContextOptions().isPolyglotBuiltin() && (getEnv().isPolyglotEvalAllowed() || getEnv().isPolyglotBindingsAccessAllowed())) { + if (getContextOptions().isPolyglotBuiltin() && (getEnv().isPolyglotEvalAllowed(null) || getEnv().isPolyglotBindingsAccessAllowed())) { setupPolyglot(); } if (getContextOptions().isDebugBuiltin()) { From d4ab1539a75da60a12910636313e48d55554cbf0 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Mon, 10 Jun 2024 15:28:46 +0200 Subject: [PATCH 035/265] Avoid a potential internal error from Polyglot.eval[File](). --- .../src/com/oracle/truffle/js/builtins/PolyglotBuiltins.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/PolyglotBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/PolyglotBuiltins.java index 4e91a000d58..0c17026da5e 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/PolyglotBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/PolyglotBuiltins.java @@ -274,7 +274,7 @@ private CallTarget evalStringIntl(TruffleString sourceText, String languageId, S TruffleLanguage.Env env = getRealm().getEnv(); try { return env.parsePublic(source); - } catch (IllegalStateException ex) { + } catch (IllegalStateException | IllegalArgumentException ex) { throw Errors.createErrorFromException(ex); } } @@ -333,7 +333,7 @@ private CallTarget evalFileIntl(TruffleString fileName, String languageId, Strin try { return env.parsePublic(source); - } catch (IllegalStateException ex) { + } catch (IllegalStateException | IllegalArgumentException ex) { throw Errors.createErrorFromException(ex); } } From 2e31cd01f954e3bec825aa3bcd556202bcdee1d1 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Tue, 11 Jun 2024 10:49:43 +0200 Subject: [PATCH 036/265] Aligning one JSON.parse-related error message with V8. --- .../oracle/truffle/js/builtins/json/TruffleJSONParser.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/json/TruffleJSONParser.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/json/TruffleJSONParser.java index bc638728b9b..9e1434179d6 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/json/TruffleJSONParser.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/json/TruffleJSONParser.java @@ -206,7 +206,10 @@ private void parseJSONMemberList(JSObject object, JSRealm realm, JSONParseRecord private void parseJSONMember(JSObject object, JSRealm realm, JSONParseRecord parseRecord) { TruffleString jsonKey = getJSONString(); skipWhitespace(); - expectChar(':'); + if (get(pos) != ':') { + throw error("Expected ':' after property name in JSON"); + } + skipChar(':'); skipWhitespace(); Object jsonValue = parseJSONValue(realm); if (withSource) { From 70bbf184838692a3c4e2a6195f5cdc7a52556100 Mon Sep 17 00:00:00 2001 From: Jakub Chaloupka Date: Tue, 11 Jun 2024 13:28:17 +0200 Subject: [PATCH 037/265] Suppress ExpectedException deprecation warning. Use MatcherAssert#assertThat instead of Assert#assertThat. --- .../js/scriptengine/test/JSONCompatibleTest.java | 4 ++-- .../truffle/js/scriptengine/test/TestEngine.java | 4 ++-- .../src/com/oracle/truffle/js/test/JSTest.java | 4 ++-- .../truffle/js/test/ModuleNotFoundErrorTest.java | 2 +- .../src/com/oracle/truffle/js/test/TestHelper.java | 4 ++-- .../oracle/truffle/js/test/builtins/EvalTest.java | 4 ++-- .../truffle/js/test/builtins/GlobalProxyTest.java | 4 ++-- .../js/test/builtins/TemporalDurationHugeTest.java | 3 ++- .../js/test/interop/ClassFilterInteropTest.java | 6 +++--- .../com/oracle/truffle/js/test/interop/DateTest.java | 4 ++-- .../com/oracle/truffle/js/test/interop/GR43097.java | 4 ++-- .../js/test/interop/JavaScriptHostInteropTest.java | 2 +- .../js/test/interop/TargetTypeMappingTest.java | 2 +- .../StringToNumberTargetTypeMappingTest.java | 4 ++-- .../truffle/js/test/polyglot/InnerContextTest.java | 2 +- .../js/test/polyglot/JavaScriptLanguageTest.java | 4 ++-- .../js/test/polyglot/SandboxPolicyOptionsTest.java | 4 ++-- .../com/oracle/truffle/js/test/regress/GR17114.java | 4 ++-- .../com/oracle/truffle/js/test/regress/GR32786.java | 12 ++++++------ .../com/oracle/truffle/js/test/regress/GR32847.java | 6 +++--- .../js/test/runtime/PrivateClassMemberTest.java | 4 ++-- .../truffle/js/test/tools/ParseInlineTest.java | 4 ++-- 22 files changed, 46 insertions(+), 45 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js.scriptengine.test/src/com/oracle/truffle/js/scriptengine/test/JSONCompatibleTest.java b/graal-js/src/com.oracle.truffle.js.scriptengine.test/src/com/oracle/truffle/js/scriptengine/test/JSONCompatibleTest.java index 5e2d41d2db5..6575bced57c 100644 --- a/graal-js/src/com.oracle.truffle.js.scriptengine.test/src/com/oracle/truffle/js/scriptengine/test/JSONCompatibleTest.java +++ b/graal-js/src/com.oracle.truffle.js.scriptengine.test/src/com/oracle/truffle/js/scriptengine/test/JSONCompatibleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,8 +41,8 @@ package com.oracle.truffle.js.scriptengine.test; import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; import java.util.Arrays; import java.util.List; diff --git a/graal-js/src/com.oracle.truffle.js.scriptengine.test/src/com/oracle/truffle/js/scriptengine/test/TestEngine.java b/graal-js/src/com.oracle.truffle.js.scriptengine.test/src/com/oracle/truffle/js/scriptengine/test/TestEngine.java index 446d4844d47..5339e345acc 100644 --- a/graal-js/src/com.oracle.truffle.js.scriptengine.test/src/com/oracle/truffle/js/scriptengine/test/TestEngine.java +++ b/graal-js/src/com.oracle.truffle.js.scriptengine.test/src/com/oracle/truffle/js/scriptengine/test/TestEngine.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -76,7 +76,7 @@ public class TestEngine { private final ScriptEngineManager manager = new ScriptEngineManager(); - @Rule public ExpectedException expectedException = ExpectedException.none(); + @SuppressWarnings("deprecation") @Rule public ExpectedException expectedException = ExpectedException.none(); private ScriptEngine getEngine() { return manager.getEngineByName(TESTED_ENGINE_NAME); diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/JSTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/JSTest.java index 62dadfb7d9f..e431fd9b223 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/JSTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/JSTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,7 +41,7 @@ package com.oracle.truffle.js.test; import static org.hamcrest.CoreMatchers.startsWith; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/ModuleNotFoundErrorTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/ModuleNotFoundErrorTest.java index e958b4a95c3..f4ee5479100 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/ModuleNotFoundErrorTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/ModuleNotFoundErrorTest.java @@ -42,7 +42,7 @@ import static org.hamcrest.CoreMatchers.allOf; import static org.hamcrest.CoreMatchers.containsString; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/TestHelper.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/TestHelper.java index 032dc8f70ae..57c53dc625c 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/TestHelper.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/TestHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,8 +41,8 @@ package com.oracle.truffle.js.test; import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import java.io.ByteArrayOutputStream; diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/EvalTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/EvalTest.java index ff5d7d1f9f5..eeb490b311e 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/EvalTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/EvalTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,9 +41,9 @@ package com.oracle.truffle.js.test.builtins; import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.io.ByteArrayOutputStream; diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/GlobalProxyTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/GlobalProxyTest.java index 04cd930d590..439f3e7c174 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/GlobalProxyTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/GlobalProxyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,8 +41,8 @@ package com.oracle.truffle.js.test.builtins; import static org.hamcrest.CoreMatchers.startsWith; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import java.io.ByteArrayOutputStream; diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/TemporalDurationHugeTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/TemporalDurationHugeTest.java index 70f4f2156dc..8130fb9006f 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/TemporalDurationHugeTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/TemporalDurationHugeTest.java @@ -46,6 +46,7 @@ import org.graalvm.polyglot.Context; import org.graalvm.polyglot.PolyglotException; import org.hamcrest.CoreMatchers; +import org.hamcrest.MatcherAssert; import org.junit.Assert; import org.junit.Test; @@ -140,7 +141,7 @@ private static void assertThrowsRangeError(String code) { ctx.eval(ID, code); Assert.fail("RangeError expected"); } catch (PolyglotException ex) { - Assert.assertThat(ex.getMessage(), CoreMatchers.startsWith("RangeError")); + MatcherAssert.assertThat(ex.getMessage(), CoreMatchers.startsWith("RangeError")); } } diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ClassFilterInteropTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ClassFilterInteropTest.java index 8b71350e455..fccba8eacd3 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ClassFilterInteropTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ClassFilterInteropTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,8 +41,8 @@ package com.oracle.truffle.js.test.interop; import static com.oracle.truffle.js.lang.JavaScriptLanguage.ID; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import java.util.function.Predicate; @@ -66,7 +66,7 @@ */ public class ClassFilterInteropTest { - @Rule public ExpectedException expectedException = ExpectedException.none(); + @SuppressWarnings("deprecation") @Rule public ExpectedException expectedException = ExpectedException.none(); public static class MyClass { @Export diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/DateTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/DateTest.java index da8541105bc..957ce78cf02 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/DateTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/DateTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -42,9 +42,9 @@ import static com.oracle.truffle.js.lang.JavaScriptLanguage.ID; import static org.hamcrest.CoreMatchers.startsWith; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.time.Instant; diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/GR43097.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/GR43097.java index 346e82901a8..d1091ed51b3 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/GR43097.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/GR43097.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,10 +41,10 @@ package com.oracle.truffle.js.test.interop; import static org.hamcrest.CoreMatchers.startsWith; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/JavaScriptHostInteropTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/JavaScriptHostInteropTest.java index 6f4293e2472..c23850906ee 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/JavaScriptHostInteropTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/JavaScriptHostInteropTest.java @@ -43,10 +43,10 @@ import static com.oracle.truffle.js.lang.JavaScriptLanguage.ID; import static com.oracle.truffle.js.test.JSTest.assertThrows; import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/TargetTypeMappingTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/TargetTypeMappingTest.java index 05ef0a7d9f6..74d52e16781 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/TargetTypeMappingTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/TargetTypeMappingTest.java @@ -64,7 +64,7 @@ * {@link HostAccess.Builder#targetTypeMapping}. */ public class TargetTypeMappingTest { - @Rule public ExpectedException expectedException = ExpectedException.none(); + @SuppressWarnings("deprecation") @Rule public ExpectedException expectedException = ExpectedException.none(); public static class ToBePassedToJS { private JsonObject jsonObject; diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/specific/StringToNumberTargetTypeMappingTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/specific/StringToNumberTargetTypeMappingTest.java index ae14d147d8b..31932df382a 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/specific/StringToNumberTargetTypeMappingTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/specific/StringToNumberTargetTypeMappingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -92,7 +92,7 @@ public static Collection data() { }); } - @Rule public ExpectedException expectedException = ExpectedException.none(); + @SuppressWarnings("deprecation") @Rule public ExpectedException expectedException = ExpectedException.none(); private Context context; diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/polyglot/InnerContextTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/polyglot/InnerContextTest.java index e87d8e900a8..fa13cca28ca 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/polyglot/InnerContextTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/polyglot/InnerContextTest.java @@ -154,7 +154,7 @@ private Object innerJS() { } } - @Rule public final ExpectedException exception = ExpectedException.none(); + @SuppressWarnings("deprecation") @Rule public final ExpectedException exception = ExpectedException.none(); @Test public void innerParseWithArgumentsHasLocalEnvironment() throws Exception { diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/polyglot/JavaScriptLanguageTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/polyglot/JavaScriptLanguageTest.java index f458cd4a47c..3d1063eb86e 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/polyglot/JavaScriptLanguageTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/polyglot/JavaScriptLanguageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -43,9 +43,9 @@ import static org.hamcrest.CoreMatchers.allOf; import static org.hamcrest.CoreMatchers.endsWith; import static org.hamcrest.CoreMatchers.startsWith; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import java.io.ByteArrayOutputStream; diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/polyglot/SandboxPolicyOptionsTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/polyglot/SandboxPolicyOptionsTest.java index 1ca815f4893..2642b6fc60a 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/polyglot/SandboxPolicyOptionsTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/polyglot/SandboxPolicyOptionsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -93,7 +93,7 @@ public static Collection parameters() { return policies.stream().flatMap(p -> options.stream().map(o -> new Object[]{p, o})).toList(); } - @Rule public ExpectedException expectedException = ExpectedException.none(); + @SuppressWarnings("deprecation") @Rule public ExpectedException expectedException = ExpectedException.none(); @Test public void testSettableOptions() { diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR17114.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR17114.java index bf211e2a58a..cb491221f8c 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR17114.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR17114.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,9 +41,9 @@ package com.oracle.truffle.js.test.regress; import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import org.graalvm.polyglot.Context; diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR32786.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR32786.java index e57ad322ae4..d8de40b63b5 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR32786.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR32786.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,6 +41,7 @@ package com.oracle.truffle.js.test.regress; import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.fail; import java.io.ByteArrayOutputStream; @@ -52,7 +53,6 @@ import org.graalvm.polyglot.PolyglotException; import org.graalvm.polyglot.Source; import org.graalvm.polyglot.Value; -import org.junit.Assert; import org.junit.Test; import com.oracle.truffle.js.test.JSTest; @@ -90,8 +90,8 @@ async function someJsFun() { }; asyncPromise.invokeMember("catch", javaThen); - Assert.assertThat(out.toString(), containsString("expected message")); - Assert.assertThat(out.toString(), containsString("someJsFun(async-snippet")); + assertThat(out.toString(), containsString("expected message")); + assertThat(out.toString(), containsString("someJsFun(async-snippet")); } } @@ -114,8 +114,8 @@ function someJsFun() { fail("should have thrown a PolyglotException"); } catch (PolyglotException ex) { ex.printStackTrace(new PrintStream(out)); - Assert.assertThat(out.toString(), containsString("expected message")); - Assert.assertThat(out.toString(), containsString("someJsFun(sync-snippet")); + assertThat(out.toString(), containsString("expected message")); + assertThat(out.toString(), containsString("someJsFun(sync-snippet")); } } } diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR32847.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR32847.java index 9f9e1667a9c..89f232b929a 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR32847.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR32847.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -50,7 +50,7 @@ import org.graalvm.polyglot.Context; import org.graalvm.polyglot.Source; import org.graalvm.polyglot.Value; -import org.junit.Assert; +import org.hamcrest.MatcherAssert; import org.junit.Test; import com.oracle.truffle.js.test.JSTest; @@ -97,7 +97,7 @@ async function main() { // (4) asyncPromise.invokeMember("catch", javaThen); - Assert.assertThat(out.toString(), allOf( + MatcherAssert.assertThat(out.toString(), allOf( containsString("throwException("), containsString("foo(Unnamed"), containsString("main(Unnamed"))); diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/runtime/PrivateClassMemberTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/runtime/PrivateClassMemberTest.java index 42ce9ab0b45..abf793ae367 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/runtime/PrivateClassMemberTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/runtime/PrivateClassMemberTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -42,7 +42,7 @@ import static com.oracle.truffle.js.lang.JavaScriptLanguage.ID; import static com.oracle.truffle.js.runtime.JSContextOptions.ECMASCRIPT_VERSION_NAME; -import static org.junit.Assert.assertThat; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/tools/ParseInlineTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/tools/ParseInlineTest.java index 87ffe26db49..2fe007bc6df 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/tools/ParseInlineTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/tools/ParseInlineTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,9 +41,9 @@ package com.oracle.truffle.js.test.tools; import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import org.graalvm.polyglot.Context; From 23be8f4ffc8b2e5243696dd9f021463232fc4f97 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Tue, 11 Jun 2024 10:51:37 +0200 Subject: [PATCH 038/265] Allow graal-js variants of error messages in test-esm-cjs-exports and test-esm-detect-ambiguous. --- graal-nodejs/test/es-module/test-esm-cjs-exports.js | 2 +- graal-nodejs/test/es-module/test-esm-detect-ambiguous.mjs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/graal-nodejs/test/es-module/test-esm-cjs-exports.js b/graal-nodejs/test/es-module/test-esm-cjs-exports.js index 4f79d2ce4bc..2dfc16f1067 100644 --- a/graal-nodejs/test/es-module/test-esm-cjs-exports.js +++ b/graal-nodejs/test/es-module/test-esm-cjs-exports.js @@ -24,6 +24,6 @@ describe('ESM: importing CJS', { concurrency: true }, () => { assert.strictEqual(code, 1); assert.strictEqual(signal, null); assert.ok(stderr.includes('Warning: To load an ES module')); - assert.ok(stderr.includes('Unexpected token \'export\'')); + assert.ok(stderr.includes('Unexpected token \'export\'') || stderr.includes('Expected an operand but found export')); }); }); diff --git a/graal-nodejs/test/es-module/test-esm-detect-ambiguous.mjs b/graal-nodejs/test/es-module/test-esm-detect-ambiguous.mjs index fc50e8d6c93..3a0738f4e0d 100644 --- a/graal-nodejs/test/es-module/test-esm-detect-ambiguous.mjs +++ b/graal-nodejs/test/es-module/test-esm-detect-ambiguous.mjs @@ -321,7 +321,7 @@ describe('--experimental-detect-module', { concurrency: true }, () => { 'function fn() { const require = 1; const require = 2; } fn();', ]); - match(stderr, /SyntaxError: Identifier 'require' has already been declared/); + match(stderr, /SyntaxError: (?:Identifier|Variable) .require. has already been declared/); strictEqual(stdout, ''); strictEqual(code, 1); strictEqual(signal, null); From e689132c0d730de968a6b937b01925e56cbe8f62 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Tue, 11 Jun 2024 10:52:33 +0200 Subject: [PATCH 039/265] Updating the status of es-module test-suite. --- graal-nodejs/test/es-module/es-module.status | 8 -------- 1 file changed, 8 deletions(-) diff --git a/graal-nodejs/test/es-module/es-module.status b/graal-nodejs/test/es-module/es-module.status index 2aab9c97eef..6fdd3b87e0a 100644 --- a/graal-nodejs/test/es-module/es-module.status +++ b/graal-nodejs/test/es-module/es-module.status @@ -8,14 +8,6 @@ prefix es-module ### Graal.js-specific ### -# Different error message expected: -# 'Unexpected token export' versus 'Expected an operand but found export' -test-esm-cjs-exports : FAIL -# 'await is only valid in async function' versus 'Expected ; but found Promise' -test-esm-detect-ambiguous : FAIL -# 'Unexpected token }' verus ': expected' -test-esm-invalid-pjson : FAIL - # missing support for source maps test-esm-loader-hooks : FAIL test-esm-source-map : FAIL From 61991d991cdf09140065f4ca6fd2fbbff5e9a0ad Mon Sep 17 00:00:00 2001 From: Tomas Zezula Date: Fri, 7 Jun 2024 15:50:03 +0200 Subject: [PATCH 040/265] Add jsnative option to mx_graal_js to simplify building a native executable using an unchained GraalVM. --- graal-js/mx.graal-js/mx_graal_js.py | 46 +++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/graal-js/mx.graal-js/mx_graal_js.py b/graal-js/mx.graal-js/mx_graal_js.py index 2d753a73578..ce1ccc12504 100644 --- a/graal-js/mx.graal-js/mx_graal_js.py +++ b/graal-js/mx.graal-js/mx_graal_js.py @@ -381,6 +381,51 @@ def _fetch_test262(): else: mx.GitConfig().update(_location, rev=TEST262_REV, mayPull=True, abortOnError=True) +def jsnative(args): + """builds and executes native JS image""" + parser = mx_truffle.ArgumentParser(prog='mx jsnative', description='Builds and executes native JS image.', usage='mx jsnative [--target-folder |@VM options|--|JS args]') + parser.add_argument('--target-folder', help='Folder where the JS executable will be generated.', default=None) + parsed_args, args = parser.parse_known_args(args) + vm_args, js_args = mx.extract_VM_args(args, useDoubleDash=True, defaultAllVMArgs=False) + target_dir = parsed_args.target_folder if parsed_args.target_folder else tempfile.mkdtemp() + if not exists(target_dir): + os.mkdir(target_dir) + jdk = mx.get_jdk(tag='graalvm') + image = _native_image_js(jdk, vm_args, target_dir, use_optimized_runtime=True, hosted_assertions=False) + if js_args: + mx.log("Image build completed. Running {}".format(" ".join([image] + js_args))) + return mx.run([image] + js_args) + else: + mx.log(f"Image build completed. JavaScript image has been generated at {image}.") + return 0 + +def resolve_js_dist_names(use_optimized_runtime=True, use_enterprise=True): + return ['GRAALJS', 'GRAALJS_LAUNCHER'] + mx_truffle.resolve_truffle_dist_names(use_optimized_runtime=use_optimized_runtime, use_enterprise=use_enterprise) + +def _native_image_js(jdk, vm_args, target_dir, use_optimized_runtime=True, use_enterprise=True, hosted_assertions=True): + native_image_args = list(vm_args) + native_image_path = _native_image(jdk) + target_path = os.path.join(target_dir, mx.exe_suffix('js')) + dist_names = resolve_js_dist_names(use_optimized_runtime=use_optimized_runtime, use_enterprise=use_enterprise) + + if hosted_assertions: + native_image_args += ["-J-ea", "-J-esa"] + + native_image_args += mx.get_runtime_jvm_args(names=dist_names) + native_image_args += ["com.oracle.truffle.js.shell.JSLauncher"] + native_image_args += [target_path] + mx.log("Running {} {}".format(mx.exe_suffix('native-image'), " ".join(native_image_args))) + mx.run([native_image_path] + native_image_args) + return target_path + +def _native_image(jdk): + native_image_path = jdk.exe_path('native-image') + if not exists(native_image_path): + native_image_path = os.path.join(jdk.home, 'bin', mx.cmd_suffix('native-image')) + if not exists(native_image_path): + mx.abort("No native-image installed in GraalVM {}. Switch to an environment that has an installed native-image command.".format(jdk.home)) + return native_image_path + def testnashorn(args, nonZeroIsFatal=True): """run the testNashorn conformance suite""" _location = join(_suite.dir, 'lib', 'testnashorn') @@ -565,6 +610,7 @@ def verify_ci(args): mx.update_commands(_suite, { 'deploy-binary-if-master' : [deploy_binary_if_master, ''], 'js' : [js, '[JS args|VM options]'], + 'jsnative': [jsnative, '[--target-folder |@VM options|--|JS args]'], 'nashorn' : [nashorn, '[JS args|VM options]'], 'test262': [test262, ''], 'testnashorn': [testnashorn, ''], From 68612969d61dd5734a7a0b7e0dfdc085ab26ef87 Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Thu, 6 Jun 2024 14:16:50 +0200 Subject: [PATCH 041/265] Start next dev cycle. --- graal-js/mx.graal-js/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/mx.graal-js/suite.py b/graal-js/mx.graal-js/suite.py index c7cc9f11fa5..059df736511 100644 --- a/graal-js/mx.graal-js/suite.py +++ b/graal-js/mx.graal-js/suite.py @@ -3,7 +3,7 @@ "name" : "graal-js", - "version" : "24.1.0", + "version" : "24.2.0", "release" : False, "groupId" : "org.graalvm.js", "url" : "http://www.graalvm.org/", From 62d4e622909aa205c1933619f29417f0018acfd3 Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Wed, 12 Jun 2024 16:52:30 +0200 Subject: [PATCH 042/265] Update graal imports to the new dev cycle. --- common.json | 16 ++++++++-------- graal-js/mx.graal-js/suite.py | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/common.json b/common.json index d811baf1cf2..482ad596be2 100644 --- a/common.json +++ b/common.json @@ -8,7 +8,7 @@ "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { - "galahad-jdk": {"name": "jpg-jdk", "version": "23", "build_id": "jdk-23+25-2038", "platformspecific": true, "extrabundles": ["static-libs"]}, + "galahad-jdk": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+1-1", "platformspecific": true, "extrabundles": ["static-libs"]}, "oraclejdk11": {"name": "jpg-jdk", "version": "11.0.11", "build_id": "jdk-11.0.11+9", "platformspecific": true, "extrabundles": ["static-libs"] }, @@ -45,13 +45,13 @@ "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.2+13-jvmci-23.1-b33-sulong", "platformspecific": true }, "graalvm-ee-21": {"name": "graalvm-java21", "version": "23.1.3", "platformspecific": true }, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "23", "build_id": "jdk-23+25", "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-23+25-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-23+25-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-23+25-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-23+25-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-23+25-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-23+25-jvmci-b01-sulong", "platformspecific": true } + "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+1", "platformspecific": true, "extrabundles": ["static-libs"]}, + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+1-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+1-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+1-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+1-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+1-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+1-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { diff --git a/graal-js/mx.graal-js/suite.py b/graal-js/mx.graal-js/suite.py index 059df736511..a28832724c0 100644 --- a/graal-js/mx.graal-js/suite.py +++ b/graal-js/mx.graal-js/suite.py @@ -24,7 +24,7 @@ { "name" : "regex", "subdir" : True, - "version" : "11f7b2aa55277324decc1377ca06eb61443c4d23", + "version" : "af0d8606f490f24c1aebe23e3b6aea693dfd6576", "urls" : [ {"url" : "https://github.com/oracle/graal.git", "kind" : "git"}, ] From e593be4319e6ba365634e650a2739ed1ecb8b1fe Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 13 Jun 2024 00:38:46 +0200 Subject: [PATCH 043/265] Implement Promise.try proposal. --- .../js/builtins/PromiseFunctionBuiltins.java | 51 ++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/PromiseFunctionBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/PromiseFunctionBuiltins.java index c3495a50496..6d4be89d1c9 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/PromiseFunctionBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/PromiseFunctionBuiltins.java @@ -46,6 +46,7 @@ import com.oracle.truffle.api.exception.AbstractTruffleException; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.js.builtins.PromiseFunctionBuiltinsFactory.PromiseCombinatorNodeGen; +import com.oracle.truffle.js.builtins.PromiseFunctionBuiltinsFactory.PromiseTryNodeGen; import com.oracle.truffle.js.builtins.PromiseFunctionBuiltinsFactory.RejectNodeGen; import com.oracle.truffle.js.builtins.PromiseFunctionBuiltinsFactory.ResolveNodeGen; import com.oracle.truffle.js.builtins.PromiseFunctionBuiltinsFactory.WithResolversNodeGen; @@ -100,7 +101,9 @@ public enum PromiseFunction implements BuiltinEnum { allSettled(1), any(1), - withResolvers(0); + withResolvers(0), + + try_(1); private final int length; @@ -119,6 +122,7 @@ public int getECMAScriptVersion() { case any -> JSConfig.ECMAScript2021; case allSettled -> JSConfig.ECMAScript2020; case withResolvers -> JSConfig.ECMAScript2024; + case try_ -> JSConfig.StagingECMAScriptVersion; default -> JSConfig.ECMAScript2015; }; } @@ -141,6 +145,8 @@ protected Object createNode(JSContext context, JSBuiltin builtin, boolean constr return ResolveNodeGen.create(context, builtin, args().withThis().fixedArgs(1).createArgumentNodes(context)); case withResolvers: return WithResolversNodeGen.create(context, builtin, args().withThis().createArgumentNodes(context)); + case try_: + return PromiseTryNodeGen.create(context, builtin, args().withThis().fixedArgs(1).varArgs().createArgumentNodes(context)); } return null; } @@ -290,4 +296,47 @@ protected JSObject withResolvers(VirtualFrame frame, Object thiz) { } } + + public abstract static class PromiseTryNode extends JSBuiltinNode { + @Child private NewPromiseCapabilityNode newPromiseCapabilityNode; + @Child private JSFunctionCallNode callCallbackFnNode; + @Child private JSFunctionCallNode callResolveNode; + @Child private JSFunctionCallNode callRejectNode; + @Child private TryCatchNode.GetErrorObjectNode getErrorObjectNode; + + protected PromiseTryNode(JSContext context, JSBuiltin builtin) { + super(context, builtin); + this.newPromiseCapabilityNode = NewPromiseCapabilityNode.create(context); + this.callCallbackFnNode = JSFunctionCallNode.createCall(); + this.callResolveNode = JSFunctionCallNode.createCall(); + } + + @Specialization + protected final Object doObject(JSObject constructor, Object callbackfn, Object[] args) { + PromiseCapabilityRecord promiseCapability = newPromiseCapabilityNode.execute(constructor); + try { + Object status = callCallbackFnNode.executeCall(JSArguments.create(Undefined.instance, callbackfn, args)); + callResolveNode.executeCall(JSArguments.createOneArg(Undefined.instance, promiseCapability.getResolve(), status)); + } catch (AbstractTruffleException ex) { + rejectPromise(ex, promiseCapability); + } + return promiseCapability.getPromise(); + } + + private void rejectPromise(AbstractTruffleException ex, PromiseCapabilityRecord promiseCapability) { + if (callRejectNode == null || getErrorObjectNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + callRejectNode = insert(JSFunctionCallNode.createCall()); + getErrorObjectNode = insert(TryCatchNode.GetErrorObjectNode.create(getContext())); + } + Object error = getErrorObjectNode.execute(ex); + callRejectNode.executeCall(JSArguments.createOneArg(Undefined.instance, promiseCapability.getReject(), error)); + } + + @SuppressWarnings("unused") + @Specialization(guards = "!isJSObject(thisObj)") + protected static Object doNotObject(Object thisObj, Object callbackfn, Object[] args) { + throw Errors.createTypeError("Cannot create promise from this type"); + } + } } From 771cc8bea9de33af8f919f4c1d3d49642e8e4ee3 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 13 Jun 2024 00:44:01 +0200 Subject: [PATCH 044/265] Add promise-try to supported test262 features. --- .../truffle/js/test/external/test262/Test262Runnable.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java index 08f0f3793de..d37482d7b61 100644 --- a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java +++ b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java @@ -241,6 +241,7 @@ public class Test262Runnable extends TestRunnable { "object-spread", "optional-catch-binding", "optional-chaining", + "promise-try", "promise-with-resolvers", "proxy-missing-checks", "regexp-dotall", @@ -265,7 +266,6 @@ public class Test262Runnable extends TestRunnable { "Intl.DurationFormat", "IsHTMLDDA", "explicit-resource-management", - "promise-try", "regexp-modifiers", "tail-call-optimization", }); @@ -277,6 +277,7 @@ public class Test262Runnable extends TestRunnable { "ShadowRealm", "decorators", "json-parse-with-source", + "promise-try", }); public Test262Runnable(TestSuite suite, TestFile testFile) { From 346f9be93b95c34773043ac02b5a4336b28a1fb6 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Thu, 13 Jun 2024 13:47:21 +0200 Subject: [PATCH 045/265] Distinguish fixed and auto length TypedArrays. --- .../builtins/DataViewPrototypeBuiltins.java | 12 +- .../builtins/JSConstructTypedArrayNode.java | 10 +- .../builtins/TypedArrayPrototypeBuiltins.java | 6 +- .../js/nodes/wasm/ExportByteSourceNode.java | 2 +- .../truffle/js/runtime/array/TypedArray.java | 184 +++++++++--------- .../js/runtime/array/TypedArrayFactory.java | 140 +++++++------ .../runtime/builtins/JSArrayBufferView.java | 2 +- .../runtime/builtins/JSTypedArrayObject.java | 5 + .../wasm/JSWebAssemblyMemoryWaitCallback.java | 4 +- .../truffle/trufflenode/GraalJSAccess.java | 2 +- .../serialization/Deserializer.java | 2 +- 11 files changed, 194 insertions(+), 175 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DataViewPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DataViewPrototypeBuiltins.java index 19f0cad77ef..3fd467a45d4 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DataViewPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DataViewPrototypeBuiltins.java @@ -271,7 +271,7 @@ public abstract static class GetBufferElementNode extends JavaScriptBaseNode { static Object doHeapArrayBuffer(JSArrayBufferObject.Heap buffer, int bufferIndex, boolean littleEndian, TypedArrayFactory factory) { assert !JSArrayBuffer.isJSInteropArrayBuffer(buffer) && !JSArrayBuffer.isJSDirectOrSharedArrayBuffer(buffer) : buffer; CompilerAsserts.partialEvaluationConstant(factory); - TypedArray strategy = factory.createArrayType(false, true, false); + TypedArray strategy = factory.createArrayType(false, true, false, false); CompilerAsserts.partialEvaluationConstant(strategy); return strategy.getBufferElement(buffer, bufferIndex, littleEndian, null); } @@ -280,7 +280,7 @@ static Object doHeapArrayBuffer(JSArrayBufferObject.Heap buffer, int bufferIndex static Object doDirectOrSharedArrayBuffer(JSArrayBufferObject.DirectBase buffer, int bufferIndex, boolean littleEndian, TypedArrayFactory factory) { assert !JSArrayBuffer.isJSInteropArrayBuffer(buffer) && JSArrayBuffer.isJSDirectOrSharedArrayBuffer(buffer) : buffer; CompilerAsserts.partialEvaluationConstant(factory); - TypedArray strategy = factory.createArrayType(true, true, false); + TypedArray strategy = factory.createArrayType(true, true, false, false); CompilerAsserts.partialEvaluationConstant(strategy); return strategy.getBufferElement(buffer, bufferIndex, littleEndian, null); } @@ -290,7 +290,7 @@ static Object doInteropBuffer(JSArrayBufferObject.Interop buffer, int bufferInde @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { assert JSArrayBuffer.isJSInteropArrayBuffer(buffer) && !JSArrayBuffer.isJSDirectOrSharedArrayBuffer(buffer) : buffer; CompilerAsserts.partialEvaluationConstant(factory); - TypedArray strategy = factory.createArrayType(false, true, true); + TypedArray strategy = factory.createArrayType(false, true, false, true); CompilerAsserts.partialEvaluationConstant(strategy); return strategy.getBufferElement(buffer, bufferIndex, littleEndian, interop); } @@ -352,7 +352,7 @@ public abstract static class SetBufferElementNode extends JavaScriptBaseNode { static void doHeapArrayBuffer(JSArrayBufferObject.Heap buffer, int bufferIndex, boolean littleEndian, Object value, TypedArrayFactory factory) { assert !JSArrayBuffer.isJSInteropArrayBuffer(buffer) && !JSArrayBuffer.isJSDirectOrSharedArrayBuffer(buffer) : buffer; CompilerAsserts.partialEvaluationConstant(factory); - TypedArray strategy = factory.createArrayType(false, true, false); + TypedArray strategy = factory.createArrayType(false, true, false, false); CompilerAsserts.partialEvaluationConstant(strategy); strategy.setBufferElement(buffer, bufferIndex, littleEndian, value, null); } @@ -361,7 +361,7 @@ static void doHeapArrayBuffer(JSArrayBufferObject.Heap buffer, int bufferIndex, static void doDirectOrSharedArrayBuffer(JSArrayBufferObject.DirectBase buffer, int bufferIndex, boolean littleEndian, Object value, TypedArrayFactory factory) { assert !JSArrayBuffer.isJSInteropArrayBuffer(buffer) && JSArrayBuffer.isJSDirectOrSharedArrayBuffer(buffer) : buffer; CompilerAsserts.partialEvaluationConstant(factory); - TypedArray strategy = factory.createArrayType(true, true, false); + TypedArray strategy = factory.createArrayType(true, true, false, false); CompilerAsserts.partialEvaluationConstant(strategy); strategy.setBufferElement(buffer, bufferIndex, littleEndian, value, null); } @@ -371,7 +371,7 @@ static void doInteropBuffer(JSArrayBufferObject.Interop buffer, int bufferIndex, @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { assert JSArrayBuffer.isJSInteropArrayBuffer(buffer) && !JSArrayBuffer.isJSDirectOrSharedArrayBuffer(buffer) : buffer; CompilerAsserts.partialEvaluationConstant(factory); - TypedArray strategy = factory.createArrayType(false, true, true); + TypedArray strategy = factory.createArrayType(false, true, false, true); CompilerAsserts.partialEvaluationConstant(strategy); strategy.setBufferElement(buffer, bufferIndex, littleEndian, value, interop); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/JSConstructTypedArrayNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/JSConstructTypedArrayNode.java index da8b5cca9d9..495e0429e44 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/JSConstructTypedArrayNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/JSConstructTypedArrayNode.java @@ -227,7 +227,7 @@ private JSDynamicObject doArrayBufferImpl(JSArrayBufferObject arrayBuffer, Objec } assert byteOffset <= Integer.MAX_VALUE && length <= Integer.MAX_VALUE; - TypedArray typedArray = factory.createArrayType(direct, byteOffset != 0, isInteropBuffer); + TypedArray typedArray = factory.createArrayType(direct, byteOffset != 0, length != JSArrayBufferViewBase.AUTO_LENGTH, isInteropBuffer); return createTypedArray(arrayBuffer, typedArray, (int) byteOffset, (int) length, newTarget); } @@ -282,7 +282,7 @@ protected JSDynamicObject doTypedArray(JSDynamicObject newTarget, JSTypedArrayOb throw Errors.createTypeErrorCannotMixBigIntWithOtherTypes(this); } - TypedArray typedArray = factory.createArrayType(getContext().isOptionDirectByteBuffer(), false); + TypedArray typedArray = factory.createArrayType(getContext().isOptionDirectByteBuffer(), false, true); JSDynamicObject result = createTypedArray(arrayBuffer, typedArray, 0, (int) length, newTarget); assert typedArray == JSArrayBufferView.typedArrayGetArrayType(result); @@ -375,7 +375,7 @@ protected JSDynamicObject doObject(JSDynamicObject newTarget, JSObject object, @ SimpleArrayList values = iterableToListNode.execute(getIteratorFromMethodNode.execute(node, object, usingIterator)); int len = values.size(); JSArrayBufferObject arrayBuffer = createTypedArrayBuffer(len); - TypedArray typedArray = factory.createArrayType(getContext().isOptionDirectByteBuffer(), false); + TypedArray typedArray = factory.createArrayType(getContext().isOptionDirectByteBuffer(), false, true); JSDynamicObject obj = integerIndexedObjectCreate(arrayBuffer, typedArray, 0, len, proto); for (int k = 0; k < len; k++) { Object kValue = values.get(k); @@ -388,7 +388,7 @@ protected JSDynamicObject doObject(JSDynamicObject newTarget, JSObject object, @ long len = getLengthNode.executeLong(object); JSArrayBufferObject arrayBuffer = createTypedArrayBuffer(len); assert len <= Integer.MAX_VALUE; - TypedArray typedArray = factory.createArrayType(getContext().isOptionDirectByteBuffer(), false); + TypedArray typedArray = factory.createArrayType(getContext().isOptionDirectByteBuffer(), false, true); JSDynamicObject obj = integerIndexedObjectCreate(arrayBuffer, typedArray, 0, (int) len, proto); for (int k = 0; k < len; k++) { Object kValue = readNode.executeWithTargetAndIndex(object, k); @@ -482,7 +482,7 @@ private JSArrayBufferObject createTypedArrayBuffer(long length) { */ private JSDynamicObject createTypedArrayWithLength(long length, JSDynamicObject newTarget) { JSArrayBufferObject arrayBuffer = createTypedArrayBuffer(length); - TypedArray typedArray = factory.createArrayType(getContext().isOptionDirectByteBuffer(), false); + TypedArray typedArray = factory.createArrayType(getContext().isOptionDirectByteBuffer(), false, true); return createTypedArray(arrayBuffer, typedArray, 0, (int) length, newTarget); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java index 54f3d6283c8..dc773ff2ef6 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java @@ -536,7 +536,7 @@ private void setArrayBufferView(JSTypedArrayObject targetView, JSTypedArrayObjec sourceBuffer = cloneArrayBuffer(sourceBuffer, sourceArray, srcByteLength, srcByteOffset); if (sourceArray.isInterop()) { // cloned buffer is not an interop buffer anymore - sourceArray = sourceArray.getFactory().createArrayType(getContext().isOptionDirectByteBuffer(), false); + sourceArray = sourceArray.getFactory().createArrayType(getContext().isOptionDirectByteBuffer(), false, true); } srcByteIndex = 0; } @@ -693,8 +693,8 @@ private JSArrayBufferObject cloneArrayBuffer(JSArrayBufferObject sourceBuffer, T private JSArrayBufferObject cloneInteropArrayBuffer(JSArrayBufferObject sourceBuffer, int srcByteLength, int srcByteOffset, InteropLibrary interop) { assert JSArrayBuffer.isJSInteropArrayBuffer(sourceBuffer); boolean direct = getContext().isOptionDirectByteBuffer(); - TypedArray sourceType = TypedArrayFactory.Int8Array.createArrayType(false, false, true); - TypedArray clonedType = TypedArrayFactory.Int8Array.createArrayType(direct, false); + TypedArray sourceType = TypedArrayFactory.Int8Array.createArrayType(false, false, true, true); + TypedArray clonedType = TypedArrayFactory.Int8Array.createArrayType(direct, false, true); JSArrayBufferObject clonedArrayBuffer = direct ? JSArrayBuffer.createDirectArrayBuffer(getContext(), getRealm(), srcByteLength) : JSArrayBuffer.createArrayBuffer(getContext(), getRealm(), srcByteLength); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/wasm/ExportByteSourceNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/wasm/ExportByteSourceNode.java index 4ef2bfcc54e..cf498812569 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/wasm/ExportByteSourceNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/wasm/ExportByteSourceNode.java @@ -117,7 +117,7 @@ private Object exportBuffer(JSArrayBufferObject arrayBuffer, int offset, int len // Wrap ArrayBuffer into Uint8Array - to allow reading its bytes on WASM side boolean interop = JSArrayBuffer.isJSInteropArrayBuffer(arrayBuffer); boolean direct = JSArrayBuffer.isJSDirectArrayBuffer(arrayBuffer); - TypedArray arrayType = TypedArrayFactory.Uint8Array.createArrayType(direct, (offset != 0), interop); + TypedArray arrayType = TypedArrayFactory.Uint8Array.createArrayType(direct, (offset != 0), true, interop); return JSArrayBufferView.createArrayBufferView(context, realm, buffer, arrayType, offset, length); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArray.java index 3fd31f10ba9..0216e66c612 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArray.java @@ -40,7 +40,6 @@ */ package com.oracle.truffle.js.runtime.array; -import static com.oracle.truffle.js.runtime.builtins.JSArrayBufferView.typedArrayGetLength; import static com.oracle.truffle.js.runtime.builtins.JSArrayBufferView.typedArrayGetOffset; import java.nio.ByteBuffer; @@ -87,6 +86,7 @@ public enum ElementType { private final int bytesPerElement; private final boolean offset; + private final boolean fixedLength; private final byte bufferType; private final TruffleString name; private final TypedArrayFactory factory; @@ -95,9 +95,10 @@ public enum ElementType { protected static final byte BUFFER_TYPE_DIRECT = 1; protected static final byte BUFFER_TYPE_INTEROP = -1; - protected TypedArray(TypedArrayFactory factory, boolean offset, byte bufferType) { + protected TypedArray(TypedArrayFactory factory, boolean offset, boolean fixedLength, byte bufferType) { this.bytesPerElement = factory.getBytesPerElement(); this.offset = offset; + this.fixedLength = fixedLength; this.bufferType = bufferType; this.name = factory.getName(); this.factory = factory; @@ -110,7 +111,8 @@ public final long length(JSDynamicObject object) { @Override public final int lengthInt(JSDynamicObject object) { - return typedArrayGetLength(object); + JSTypedArrayObject typedArray = (JSTypedArrayObject) object; + return fixedLength ? typedArray.getLengthFixed() : typedArray.getLength(); } @Override @@ -286,8 +288,8 @@ protected static JSException unsupportedBufferAccess(Object buffer, UnsupportedM } public abstract static class TypedIntArray extends TypedArray { - protected TypedIntArray(TypedArrayFactory factory, boolean offset, byte bufferType) { - super(factory, offset, bufferType); + protected TypedIntArray(TypedArrayFactory factory, boolean offset, boolean fixedLength, byte bufferType) { + super(factory, offset, fixedLength, bufferType); } @Override @@ -384,8 +386,8 @@ final int lockedReadModifyWriteShort(JSTypedArrayObject typedArrayObject, int in static final int INT8_BYTES_PER_ELEMENT = 1; public static final class Int8Array extends TypedIntArray { - Int8Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_ARRAY); + Int8Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_ARRAY); } @Override @@ -415,8 +417,8 @@ public ElementType getElementType() { } public static final class DirectInt8Array extends TypedIntArray { - DirectInt8Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_DIRECT); + DirectInt8Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); } @Override @@ -458,8 +460,8 @@ public ElementType getElementType() { } public static class InteropInt8Array extends InteropOneByteIntArray { - InteropInt8Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset); + InteropInt8Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength); } @Override @@ -469,8 +471,8 @@ public ElementType getElementType() { } public abstract static class InteropOneByteIntArray extends TypedIntArray { - InteropOneByteIntArray(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_INTEROP); + InteropOneByteIntArray(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_INTEROP); } @Override @@ -517,8 +519,8 @@ static void writeBufferByte(Object buffer, int byteIndex, byte value, InteropLib static final int UINT8_BYTES_PER_ELEMENT = 1; public static final class Uint8Array extends TypedIntArray { - Uint8Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_ARRAY); + Uint8Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_ARRAY); } @Override @@ -548,8 +550,8 @@ public ElementType getElementType() { } public static final class DirectUint8Array extends TypedIntArray { - DirectUint8Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_DIRECT); + DirectUint8Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); } @Override @@ -591,8 +593,8 @@ public ElementType getElementType() { } public static final class InteropUint8Array extends InteropOneByteIntArray { - InteropUint8Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset); + InteropUint8Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength); } @Override @@ -612,8 +614,8 @@ public ElementType getElementType() { } public abstract static class AbstractUint8ClampedArray extends TypedIntArray { - private AbstractUint8ClampedArray(TypedArrayFactory factory, boolean offset, byte bufferType) { - super(factory, offset, bufferType); + private AbstractUint8ClampedArray(TypedArrayFactory factory, boolean offset, boolean fixedLength, byte bufferType) { + super(factory, offset, fixedLength, bufferType); } @Override @@ -644,8 +646,8 @@ public ElementType getElementType() { } public static final class Uint8ClampedArray extends AbstractUint8ClampedArray { - Uint8ClampedArray(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_ARRAY); + Uint8ClampedArray(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_ARRAY); } @Override @@ -670,8 +672,8 @@ public void setBufferElementIntImpl(JSArrayBufferObject buffer, int index, boole } public static final class DirectUint8ClampedArray extends AbstractUint8ClampedArray { - DirectUint8ClampedArray(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_DIRECT); + DirectUint8ClampedArray(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); } @Override @@ -696,8 +698,8 @@ public void setBufferElementIntImpl(JSArrayBufferObject buffer, int index, boole } public static final class InteropUint8ClampedArray extends AbstractUint8ClampedArray { - InteropUint8ClampedArray(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_INTEROP); + InteropUint8ClampedArray(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_INTEROP); } @Override @@ -724,8 +726,8 @@ public void setBufferElementIntImpl(JSArrayBufferObject buffer, int index, boole static final int INT16_BYTES_PER_ELEMENT = 2; public static final class Int16Array extends TypedIntArray { - Int16Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_ARRAY); + Int16Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_ARRAY); } @Override @@ -755,8 +757,8 @@ public ElementType getElementType() { } public static final class DirectInt16Array extends TypedIntArray { - DirectInt16Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_DIRECT); + DirectInt16Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); } @Override @@ -798,8 +800,8 @@ public ElementType getElementType() { } public static class InteropInt16Array extends InteropTwoByteIntArray { - InteropInt16Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset); + InteropInt16Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength); } @Override @@ -809,8 +811,8 @@ public ElementType getElementType() { } public abstract static class InteropTwoByteIntArray extends TypedIntArray { - InteropTwoByteIntArray(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_INTEROP); + InteropTwoByteIntArray(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_INTEROP); } @Override @@ -857,8 +859,8 @@ static void writeBufferShort(Object buffer, int byteIndex, short value, ByteOrde static final int UINT16_BYTES_PER_ELEMENT = 2; public static final class Uint16Array extends TypedIntArray { - Uint16Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_ARRAY); + Uint16Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_ARRAY); } @Override @@ -888,8 +890,8 @@ public ElementType getElementType() { } public static final class DirectUint16Array extends TypedIntArray { - DirectUint16Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_DIRECT); + DirectUint16Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); } @Override @@ -931,8 +933,8 @@ public ElementType getElementType() { } public static final class InteropUint16Array extends InteropTwoByteIntArray { - InteropUint16Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset); + InteropUint16Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength); } @Override @@ -954,8 +956,8 @@ public ElementType getElementType() { static final int INT32_BYTES_PER_ELEMENT = 4; public static final class Int32Array extends TypedIntArray { - Int32Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_ARRAY); + Int32Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_ARRAY); } @Override @@ -985,8 +987,8 @@ public ElementType getElementType() { } public static final class DirectInt32Array extends TypedIntArray { - DirectInt32Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_DIRECT); + DirectInt32Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); } @Override @@ -1023,8 +1025,8 @@ public ElementType getElementType() { } public static final class InteropInt32Array extends TypedIntArray { - InteropInt32Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_INTEROP); + InteropInt32Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_INTEROP); } @Override @@ -1076,8 +1078,8 @@ public ElementType getElementType() { static final int UINT32_BYTES_PER_ELEMENT = 4; public abstract static class AbstractUint32Array extends TypedIntArray { - private AbstractUint32Array(TypedArrayFactory factory, boolean offset, byte bufferType) { - super(factory, offset, bufferType); + private AbstractUint32Array(TypedArrayFactory factory, boolean offset, boolean fixedLength, byte bufferType) { + super(factory, offset, fixedLength, bufferType); } @Override @@ -1116,8 +1118,8 @@ public ElementType getElementType() { } public static final class Uint32Array extends AbstractUint32Array { - Uint32Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_ARRAY); + Uint32Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_ARRAY); } @Override @@ -1142,8 +1144,8 @@ public void setBufferElementIntImpl(JSArrayBufferObject buffer, int index, boole } public static final class DirectUint32Array extends AbstractUint32Array { - DirectUint32Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_DIRECT); + DirectUint32Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); } @Override @@ -1175,8 +1177,8 @@ public int compareExchangeInt(JSTypedArrayObject typedArray, int index, int expe } public static final class InteropUint32Array extends AbstractUint32Array { - InteropUint32Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_INTEROP); + InteropUint32Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_INTEROP); } @Override @@ -1201,8 +1203,8 @@ public void setBufferElementIntImpl(JSArrayBufferObject buffer, int index, boole } public abstract static class TypedBigIntArray extends TypedArray { - protected TypedBigIntArray(TypedArrayFactory factory, boolean offset, byte bufferType) { - super(factory, offset, bufferType); + protected TypedBigIntArray(TypedArrayFactory factory, boolean offset, boolean fixedLength, byte bufferType) { + super(factory, offset, fixedLength, bufferType); } @Override @@ -1280,8 +1282,8 @@ public BigInt compareExchangeBigInt(JSTypedArrayObject typedArray, int index, Bi static final int BIGINT64_BYTES_PER_ELEMENT = 8; public static final class BigInt64Array extends TypedBigIntArray { - BigInt64Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_ARRAY); + BigInt64Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_ARRAY); } @Override @@ -1311,8 +1313,8 @@ public ElementType getElementType() { } public static final class DirectBigInt64Array extends TypedBigIntArray { - DirectBigInt64Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_DIRECT); + DirectBigInt64Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); } @Override @@ -1353,8 +1355,8 @@ public ElementType getElementType() { } public static class InteropBigInt64Array extends InteropBigIntArray { - InteropBigInt64Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset); + InteropBigInt64Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength); } @Override @@ -1364,8 +1366,8 @@ public ElementType getElementType() { } public abstract static class InteropBigIntArray extends TypedBigIntArray { - InteropBigIntArray(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_INTEROP); + InteropBigIntArray(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_INTEROP); } @Override @@ -1412,8 +1414,8 @@ static void writeBufferLong(Object buffer, int byteIndex, long value, ByteOrder static final int BIGUINT64_BYTES_PER_ELEMENT = 8; public static final class BigUint64Array extends TypedBigIntArray { - BigUint64Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_ARRAY); + BigUint64Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_ARRAY); } @Override @@ -1453,8 +1455,8 @@ public ElementType getElementType() { } public static final class DirectBigUint64Array extends TypedBigIntArray { - DirectBigUint64Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_DIRECT); + DirectBigUint64Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); } @Override @@ -1505,8 +1507,8 @@ public ElementType getElementType() { } public static final class InteropBigUint64Array extends InteropBigIntArray { - InteropBigUint64Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset); + InteropBigUint64Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength); } @Override @@ -1526,8 +1528,8 @@ public ElementType getElementType() { } public abstract static class TypedFloatArray extends TypedArray { - protected TypedFloatArray(TypedArrayFactory factory, boolean offset, byte bufferType) { - super(factory, offset, bufferType); + protected TypedFloatArray(TypedArrayFactory factory, boolean offset, boolean fixedLength, byte bufferType) { + super(factory, offset, fixedLength, bufferType); } @Override @@ -1569,8 +1571,8 @@ public final void setDouble(JSDynamicObject object, int index, double value, Int static final int FLOAT16_BYTES_PER_ELEMENT = 2; public static final class Float16Array extends TypedFloatArray { - Float16Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_ARRAY); + Float16Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_ARRAY); } @Override @@ -1600,8 +1602,8 @@ public ElementType getElementType() { } public static final class DirectFloat16Array extends TypedFloatArray { - DirectFloat16Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_DIRECT); + DirectFloat16Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); } @Override @@ -1631,8 +1633,8 @@ public ElementType getElementType() { } public static final class InteropFloat16Array extends TypedFloatArray { - InteropFloat16Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_INTEROP); + InteropFloat16Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_INTEROP); } @Override @@ -1684,8 +1686,8 @@ public ElementType getElementType() { static final int FLOAT32_BYTES_PER_ELEMENT = 4; public static final class Float32Array extends TypedFloatArray { - Float32Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_ARRAY); + Float32Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_ARRAY); } @Override @@ -1715,8 +1717,8 @@ public ElementType getElementType() { } public static final class DirectFloat32Array extends TypedFloatArray { - DirectFloat32Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_DIRECT); + DirectFloat32Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); } @Override @@ -1746,8 +1748,8 @@ public ElementType getElementType() { } public static final class InteropFloat32Array extends TypedFloatArray { - InteropFloat32Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_INTEROP); + InteropFloat32Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_INTEROP); } @Override @@ -1799,8 +1801,8 @@ public ElementType getElementType() { static final int FLOAT64_BYTES_PER_ELEMENT = 8; public static final class Float64Array extends TypedFloatArray { - Float64Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_ARRAY); + Float64Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_ARRAY); } @Override @@ -1830,8 +1832,8 @@ public ElementType getElementType() { } public static final class DirectFloat64Array extends TypedFloatArray { - DirectFloat64Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_DIRECT); + DirectFloat64Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); } @Override @@ -1861,8 +1863,8 @@ public ElementType getElementType() { } public static final class InteropFloat64Array extends TypedFloatArray { - InteropFloat64Array(TypedArrayFactory factory, boolean offset) { - super(factory, offset, BUFFER_TYPE_INTEROP); + InteropFloat64Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, BUFFER_TYPE_INTEROP); } @Override diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArrayFactory.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArrayFactory.java index e8fe8ab62c4..fa02e65cc77 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArrayFactory.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArrayFactory.java @@ -87,145 +87,145 @@ public enum TypedArrayFactory implements PrototypeSupplier { Int8Array(TypedArray.INT8_BYTES_PER_ELEMENT) { @Override - TypedArray instantiateArrayType(byte bufferType, boolean offset) { + TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropInt8Array(this, offset); + return new InteropInt8Array(this, offset, fixedLength); } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectInt8Array(this, offset); + return new DirectInt8Array(this, offset, fixedLength); } else { - return new Int8Array(this, offset); + return new Int8Array(this, offset, fixedLength); } } }, Uint8Array(TypedArray.UINT8_BYTES_PER_ELEMENT) { @Override - TypedArray instantiateArrayType(byte bufferType, boolean offset) { + TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropUint8Array(this, offset); + return new InteropUint8Array(this, offset, fixedLength); } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectUint8Array(this, offset); + return new DirectUint8Array(this, offset, fixedLength); } else { - return new Uint8Array(this, offset); + return new Uint8Array(this, offset, fixedLength); } } }, Uint8ClampedArray(TypedArray.UINT8_BYTES_PER_ELEMENT) { @Override - TypedArray instantiateArrayType(byte bufferType, boolean offset) { + TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropUint8ClampedArray(this, offset); + return new InteropUint8ClampedArray(this, offset, fixedLength); } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectUint8ClampedArray(this, offset); + return new DirectUint8ClampedArray(this, offset, fixedLength); } else { - return new Uint8ClampedArray(this, offset); + return new Uint8ClampedArray(this, offset, fixedLength); } } }, Int16Array(TypedArray.INT16_BYTES_PER_ELEMENT) { @Override - TypedArray instantiateArrayType(byte bufferType, boolean offset) { + TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropInt16Array(this, offset); + return new InteropInt16Array(this, offset, fixedLength); } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectInt16Array(this, offset); + return new DirectInt16Array(this, offset, fixedLength); } else { - return new Int16Array(this, offset); + return new Int16Array(this, offset, fixedLength); } } }, Uint16Array(TypedArray.UINT16_BYTES_PER_ELEMENT) { @Override - TypedArray instantiateArrayType(byte bufferType, boolean offset) { + TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropUint16Array(this, offset); + return new InteropUint16Array(this, offset, fixedLength); } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectUint16Array(this, offset); + return new DirectUint16Array(this, offset, fixedLength); } else { - return new Uint16Array(this, offset); + return new Uint16Array(this, offset, fixedLength); } } }, Int32Array(TypedArray.INT32_BYTES_PER_ELEMENT) { @Override - TypedArray instantiateArrayType(byte bufferType, boolean offset) { + TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropInt32Array(this, offset); + return new InteropInt32Array(this, offset, fixedLength); } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectInt32Array(this, offset); + return new DirectInt32Array(this, offset, fixedLength); } else { - return new Int32Array(this, offset); + return new Int32Array(this, offset, fixedLength); } } }, Uint32Array(TypedArray.UINT32_BYTES_PER_ELEMENT) { @Override - TypedArray instantiateArrayType(byte bufferType, boolean offset) { + TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropUint32Array(this, offset); + return new InteropUint32Array(this, offset, fixedLength); } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectUint32Array(this, offset); + return new DirectUint32Array(this, offset, fixedLength); } else { - return new Uint32Array(this, offset); + return new Uint32Array(this, offset, fixedLength); } } }, Float32Array(TypedArray.FLOAT32_BYTES_PER_ELEMENT) { @Override - TypedArray instantiateArrayType(byte bufferType, boolean offset) { + TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropFloat32Array(this, offset); + return new InteropFloat32Array(this, offset, fixedLength); } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectFloat32Array(this, offset); + return new DirectFloat32Array(this, offset, fixedLength); } else { - return new Float32Array(this, offset); + return new Float32Array(this, offset, fixedLength); } } }, Float64Array(TypedArray.FLOAT64_BYTES_PER_ELEMENT) { @Override - TypedArray instantiateArrayType(byte bufferType, boolean offset) { + TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropFloat64Array(this, offset); + return new InteropFloat64Array(this, offset, fixedLength); } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectFloat64Array(this, offset); + return new DirectFloat64Array(this, offset, fixedLength); } else { - return new Float64Array(this, offset); + return new Float64Array(this, offset, fixedLength); } } }, BigInt64Array(TypedArray.BIGINT64_BYTES_PER_ELEMENT) { @Override - TypedArray instantiateArrayType(byte bufferType, boolean offset) { + TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropBigInt64Array(this, offset); + return new InteropBigInt64Array(this, offset, fixedLength); } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectBigInt64Array(this, offset); + return new DirectBigInt64Array(this, offset, fixedLength); } else { - return new BigInt64Array(this, offset); + return new BigInt64Array(this, offset, fixedLength); } } }, BigUint64Array(TypedArray.BIGUINT64_BYTES_PER_ELEMENT) { @Override - TypedArray instantiateArrayType(byte bufferType, boolean offset) { + TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropBigUint64Array(this, offset); + return new InteropBigUint64Array(this, offset, fixedLength); } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectBigUint64Array(this, offset); + return new DirectBigUint64Array(this, offset, fixedLength); } else { - return new BigUint64Array(this, offset); + return new BigUint64Array(this, offset, fixedLength); } } }, Float16Array(TypedArray.FLOAT16_BYTES_PER_ELEMENT) { @Override - TypedArray instantiateArrayType(byte bufferType, boolean offset) { + TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropFloat16Array(this, offset); + return new InteropFloat16Array(this, offset, fixedLength); } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectFloat16Array(this, offset); + return new DirectFloat16Array(this, offset, fixedLength); } else { - return new Float16Array(this, offset); + return new Float16Array(this, offset, fixedLength); } } }; @@ -234,48 +234,60 @@ TypedArray instantiateArrayType(byte bufferType, boolean offset) { private final TruffleString name; private final TypedArray arrayType; private final TypedArray arrayTypeWithOffset; + private final TypedArray arrayTypeAutoLength; + private final TypedArray arrayTypeWithOffsetAutoLength; private final TypedArray directArrayType; private final TypedArray directArrayTypeWithOffset; + private final TypedArray directArrayTypeAutoLength; + private final TypedArray directArrayTypeWithOffsetAutoLength; private final TypedArray interopArrayType; private final TypedArray interopArrayTypeWithOffset; + private final TypedArray interopArrayTypeAutoLength; + private final TypedArray interopArrayTypeWithOffsetAutoLength; TypedArrayFactory(int bytesPerElement) { this.bytesPerElement = bytesPerElement; this.name = Strings.constant(name()); - this.arrayType = instantiateArrayType(TypedArray.BUFFER_TYPE_ARRAY, false); - this.arrayTypeWithOffset = instantiateArrayType(TypedArray.BUFFER_TYPE_ARRAY, true); - this.directArrayType = instantiateArrayType(TypedArray.BUFFER_TYPE_DIRECT, false); - this.directArrayTypeWithOffset = instantiateArrayType(TypedArray.BUFFER_TYPE_DIRECT, true); - this.interopArrayType = instantiateArrayType(TypedArray.BUFFER_TYPE_INTEROP, false); - this.interopArrayTypeWithOffset = instantiateArrayType(TypedArray.BUFFER_TYPE_INTEROP, true); + this.arrayType = instantiateArrayType(TypedArray.BUFFER_TYPE_ARRAY, false, true); + this.arrayTypeWithOffset = instantiateArrayType(TypedArray.BUFFER_TYPE_ARRAY, true, true); + this.arrayTypeAutoLength = instantiateArrayType(TypedArray.BUFFER_TYPE_ARRAY, false, false); + this.arrayTypeWithOffsetAutoLength = instantiateArrayType(TypedArray.BUFFER_TYPE_ARRAY, true, false); + this.directArrayType = instantiateArrayType(TypedArray.BUFFER_TYPE_DIRECT, false, true); + this.directArrayTypeWithOffset = instantiateArrayType(TypedArray.BUFFER_TYPE_DIRECT, true, true); + this.directArrayTypeAutoLength = instantiateArrayType(TypedArray.BUFFER_TYPE_DIRECT, false, false); + this.directArrayTypeWithOffsetAutoLength = instantiateArrayType(TypedArray.BUFFER_TYPE_DIRECT, true, false); + this.interopArrayType = instantiateArrayType(TypedArray.BUFFER_TYPE_INTEROP, false, true); + this.interopArrayTypeWithOffset = instantiateArrayType(TypedArray.BUFFER_TYPE_INTEROP, true, true); + this.interopArrayTypeAutoLength = instantiateArrayType(TypedArray.BUFFER_TYPE_INTEROP, false, false); + this.interopArrayTypeWithOffsetAutoLength = instantiateArrayType(TypedArray.BUFFER_TYPE_INTEROP, true, false); assert !arrayType.hasOffset() && arrayTypeWithOffset.hasOffset() && !arrayType.isDirect() && !arrayTypeWithOffset.isDirect() && !directArrayType.hasOffset() && directArrayTypeWithOffset.hasOffset() && directArrayType.isDirect() && directArrayTypeWithOffset.isDirect() && !interopArrayType.hasOffset() && interopArrayTypeWithOffset.hasOffset() && interopArrayType.isInterop() && interopArrayTypeWithOffset.isInterop(); } - public final TypedArray createArrayType(boolean direct, boolean offset) { - return createArrayType(direct, offset, false); + public final TypedArray createArrayType(boolean direct, boolean offset, boolean fixedLength) { + return createArrayType(direct, offset, fixedLength, false); } - public final TypedArray createArrayType(boolean direct, boolean offset, boolean interop) { + public final TypedArray createArrayType(boolean direct, boolean offset, boolean fixedLength, boolean interop) { if (interop) { if (offset) { - return interopArrayTypeWithOffset; + return fixedLength ? interopArrayTypeWithOffset : interopArrayTypeWithOffsetAutoLength; } else { - return interopArrayType; + return fixedLength ? interopArrayType : interopArrayTypeAutoLength; } } else if (direct) { if (offset) { - return directArrayTypeWithOffset; + return fixedLength ? directArrayTypeWithOffset : directArrayTypeWithOffsetAutoLength; } else { - return directArrayType; + return fixedLength ? directArrayType : directArrayTypeAutoLength; } } else { if (offset) { - return arrayTypeWithOffset; + return fixedLength ? arrayTypeWithOffset : arrayTypeWithOffsetAutoLength; } else { - return arrayType; + return fixedLength ? arrayType : arrayTypeAutoLength; } } } @@ -292,7 +304,7 @@ public final TruffleString getName() { return name; } - abstract TypedArray instantiateArrayType(byte bufferType, boolean offset); + abstract TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength); @Override public final JSDynamicObject getIntrinsicDefaultProto(JSRealm realm) { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayBufferView.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayBufferView.java index c96285899c1..3fdabdced67 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayBufferView.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayBufferView.java @@ -342,7 +342,7 @@ private static JSObject createLegacyArrayBufferViewPrototype(JSRealm realm, Type byte[] byteArray = new byte[0]; JSObjectFactory bufferFactory = context.getArrayBufferFactory(); JSArrayBufferObject emptyArrayBuffer = bufferFactory.initProto(JSArrayBufferObject.createHeapArrayBuffer(bufferFactory.getShape(realm), bufferFactory.getPrototype(realm), byteArray), realm); - TypedArray arrayType = factory.createArrayType(false, false); + TypedArray arrayType = factory.createArrayType(false, false, true); Shape shape = JSShape.createPrototypeShape(context, INSTANCE, taPrototype); JSObject prototype = JSTypedArrayObject.create(shape, taPrototype, arrayType, emptyArrayBuffer, 0, 0); JSObjectUtil.setOrVerifyPrototype(context, prototype, taPrototype); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java index 027c7bb4259..6ad2ad160fa 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java @@ -78,6 +78,11 @@ public TypedArray getArrayType() { return arrayType; } + public int getLengthFixed() { + assert !hasAutoLength(); + return length; + } + public int getLength() { return hasAutoLength() ? (arrayBuffer.getByteLength() - offset) / arrayType.bytesPerElement() : length; } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyMemoryWaitCallback.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyMemoryWaitCallback.java index e4d5509f922..d5ea7e16e76 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyMemoryWaitCallback.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyMemoryWaitCallback.java @@ -147,14 +147,14 @@ private TruffleString atomicsWait(JSArrayBufferObject buffer, int address, long } private static int doVolatileGetFromBuffer(JSArrayBufferObject buffer, int intArrayOffset) { - TypedArray.TypedIntArray typedArray = (TypedArray.TypedIntArray) TypedArrayFactory.Int32Array.createArrayType(true, false); + TypedArray.TypedIntArray typedArray = (TypedArray.TypedIntArray) TypedArrayFactory.Int32Array.createArrayType(true, false, true, true); int result = typedArray.getBufferElementIntImpl(buffer, intArrayOffset, true, InteropLibrary.getUncached()); VarHandle.acquireFence(); return result; } private static BigInt doVolatileGetBigIntFromBuffer(JSArrayBufferObject buffer, int bigIntArrayOffset) { - TypedArray.TypedBigIntArray typedArray = (TypedArray.TypedBigIntArray) TypedArrayFactory.BigInt64Array.createArrayType(true, false); + TypedArray.TypedBigIntArray typedArray = (TypedArray.TypedBigIntArray) TypedArrayFactory.BigInt64Array.createArrayType(true, false, true, true); BigInt result = BigInt.valueOf(typedArray.getBufferElementLongImpl(buffer, bigIntArrayOffset, true, InteropLibrary.getUncached())); VarHandle.acquireFence(); return result; diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java index 0f7cde5116b..075419fdf3c 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java @@ -1485,7 +1485,7 @@ public int typedArrayLength(Object typedArray) { } private Object typedArrayNew(Object arrayBuffer, int offset, int length, TypedArrayFactory factory) { - TypedArray arrayType = factory.createArrayType(true, offset != 0); + TypedArray arrayType = factory.createArrayType(true, offset != 0, true); JSArrayBufferObject dynamicObject = (JSArrayBufferObject) arrayBuffer; JSContext context = JSObject.getJSContext(dynamicObject); JSRealm realm = getCurrentRealm(); diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/Deserializer.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/Deserializer.java index 5e9013e448b..3742a47071e 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/Deserializer.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/Deserializer.java @@ -462,7 +462,7 @@ private JSDynamicObject readJSArrayBufferView(JSContext context, JSRealm realm, view = JSDataView.createDataView(context, realm, arrayBuffer, offset, byteLength); } else { TypedArrayFactory factory = tag.getFactory(); - TypedArray array = factory.createArrayType(true, offset != 0); + TypedArray array = factory.createArrayType(true, offset != 0, true); int length = byteLength / factory.getBytesPerElement(); view = JSArrayBufferView.createArrayBufferView(context, realm, arrayBuffer, array, offset, length); } From a3e1caa76593613cfeea743db032aa2672c70054 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Thu, 13 Jun 2024 14:51:14 +0200 Subject: [PATCH 046/265] Avoiding some virtual calls to getByteLength(). --- .../oracle/truffle/js/runtime/array/TypedArray.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArray.java index 0216e66c612..679b1ef2eb6 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArray.java @@ -112,7 +112,18 @@ public final long length(JSDynamicObject object) { @Override public final int lengthInt(JSDynamicObject object) { JSTypedArrayObject typedArray = (JSTypedArrayObject) object; - return fixedLength ? typedArray.getLengthFixed() : typedArray.getLength(); + if (fixedLength) { + return typedArray.getLengthFixed(); + } else { + JSArrayBufferObject arrayBuffer = typedArray.getArrayBuffer(); + int byteLength = switch (bufferType) { + case BUFFER_TYPE_ARRAY -> ((JSArrayBufferObject.Heap) arrayBuffer).getByteLength(); + case BUFFER_TYPE_DIRECT -> ((JSArrayBufferObject.DirectBase) arrayBuffer).getByteLength(); + case BUFFER_TYPE_INTEROP -> ((JSArrayBufferObject.Interop) arrayBuffer).getByteLength(); + default -> throw Errors.shouldNotReachHereUnexpectedValue(bufferType); + }; + return (byteLength - getOffset(object)) / bytesPerElement; + } } @Override From f29c2f673b979846d3ee67e717be786f1a732516 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 13 Jun 2024 23:16:37 +0200 Subject: [PATCH 047/265] Update changelog. --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd3d9d65d39..bd02fad6807 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ The main focus is on user-observable behavior of the engine. Changelog may include unreleased versions. See [release calendar](https://www.graalvm.org/release-calendar/) for release dates. +## Version 24.2.0 +* Implemented the [`Promise.try`](https://github.com/tc39/proposal-promise-try) proposal. It is available in ECMAScript staging mode (`--js.ecmascript-version=staging`). + ## Version 24.1.0 * ECMAScript 2024 mode/features enabled by default. * Implemented the [Make eval-introduced global vars redeclarable](https://github.com/tc39/proposal-redeclarable-global-eval-vars) proposal. From ff51c8a2acd3518ef5922ebdb77fd7e5a85b7f75 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Thu, 13 Jun 2024 16:48:35 +0200 Subject: [PATCH 048/265] Distinguish direct and shared TypedArrays. --- .../builtins/DataViewPrototypeBuiltins.java | 14 +- .../builtins/JSConstructTypedArrayNode.java | 28 ++- .../builtins/TypedArrayPrototypeBuiltins.java | 9 +- .../js/nodes/wasm/ExportByteSourceNode.java | 14 +- .../truffle/js/runtime/array/TypedArray.java | 60 ++--- .../js/runtime/array/TypedArrayFactory.java | 222 +++++++++--------- .../runtime/builtins/JSArrayBufferView.java | 2 +- .../wasm/JSWebAssemblyMemoryWaitCallback.java | 4 +- .../truffle/trufflenode/GraalJSAccess.java | 2 +- .../serialization/Deserializer.java | 2 +- 10 files changed, 191 insertions(+), 166 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DataViewPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DataViewPrototypeBuiltins.java index 3fd467a45d4..88d7261b2d0 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DataViewPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DataViewPrototypeBuiltins.java @@ -271,7 +271,7 @@ public abstract static class GetBufferElementNode extends JavaScriptBaseNode { static Object doHeapArrayBuffer(JSArrayBufferObject.Heap buffer, int bufferIndex, boolean littleEndian, TypedArrayFactory factory) { assert !JSArrayBuffer.isJSInteropArrayBuffer(buffer) && !JSArrayBuffer.isJSDirectOrSharedArrayBuffer(buffer) : buffer; CompilerAsserts.partialEvaluationConstant(factory); - TypedArray strategy = factory.createArrayType(false, true, false, false); + TypedArray strategy = factory.createArrayType(TypedArray.BUFFER_TYPE_ARRAY, true, false); CompilerAsserts.partialEvaluationConstant(strategy); return strategy.getBufferElement(buffer, bufferIndex, littleEndian, null); } @@ -280,7 +280,8 @@ static Object doHeapArrayBuffer(JSArrayBufferObject.Heap buffer, int bufferIndex static Object doDirectOrSharedArrayBuffer(JSArrayBufferObject.DirectBase buffer, int bufferIndex, boolean littleEndian, TypedArrayFactory factory) { assert !JSArrayBuffer.isJSInteropArrayBuffer(buffer) && JSArrayBuffer.isJSDirectOrSharedArrayBuffer(buffer) : buffer; CompilerAsserts.partialEvaluationConstant(factory); - TypedArray strategy = factory.createArrayType(true, true, false, false); + // It does not matter whether we use BUFFER_TYPE_DIRECT or BUFFER_TYPE_SHARED here + TypedArray strategy = factory.createArrayType(TypedArray.BUFFER_TYPE_DIRECT, true, false); CompilerAsserts.partialEvaluationConstant(strategy); return strategy.getBufferElement(buffer, bufferIndex, littleEndian, null); } @@ -290,7 +291,7 @@ static Object doInteropBuffer(JSArrayBufferObject.Interop buffer, int bufferInde @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { assert JSArrayBuffer.isJSInteropArrayBuffer(buffer) && !JSArrayBuffer.isJSDirectOrSharedArrayBuffer(buffer) : buffer; CompilerAsserts.partialEvaluationConstant(factory); - TypedArray strategy = factory.createArrayType(false, true, false, true); + TypedArray strategy = factory.createArrayType(TypedArray.BUFFER_TYPE_INTEROP, true, false); CompilerAsserts.partialEvaluationConstant(strategy); return strategy.getBufferElement(buffer, bufferIndex, littleEndian, interop); } @@ -352,7 +353,7 @@ public abstract static class SetBufferElementNode extends JavaScriptBaseNode { static void doHeapArrayBuffer(JSArrayBufferObject.Heap buffer, int bufferIndex, boolean littleEndian, Object value, TypedArrayFactory factory) { assert !JSArrayBuffer.isJSInteropArrayBuffer(buffer) && !JSArrayBuffer.isJSDirectOrSharedArrayBuffer(buffer) : buffer; CompilerAsserts.partialEvaluationConstant(factory); - TypedArray strategy = factory.createArrayType(false, true, false, false); + TypedArray strategy = factory.createArrayType(TypedArray.BUFFER_TYPE_ARRAY, true, false); CompilerAsserts.partialEvaluationConstant(strategy); strategy.setBufferElement(buffer, bufferIndex, littleEndian, value, null); } @@ -361,7 +362,8 @@ static void doHeapArrayBuffer(JSArrayBufferObject.Heap buffer, int bufferIndex, static void doDirectOrSharedArrayBuffer(JSArrayBufferObject.DirectBase buffer, int bufferIndex, boolean littleEndian, Object value, TypedArrayFactory factory) { assert !JSArrayBuffer.isJSInteropArrayBuffer(buffer) && JSArrayBuffer.isJSDirectOrSharedArrayBuffer(buffer) : buffer; CompilerAsserts.partialEvaluationConstant(factory); - TypedArray strategy = factory.createArrayType(true, true, false, false); + // It does not matter whether we use BUFFER_TYPE_DIRECT or BUFFER_TYPE_SHARED here + TypedArray strategy = factory.createArrayType(TypedArray.BUFFER_TYPE_DIRECT, true, false); CompilerAsserts.partialEvaluationConstant(strategy); strategy.setBufferElement(buffer, bufferIndex, littleEndian, value, null); } @@ -371,7 +373,7 @@ static void doInteropBuffer(JSArrayBufferObject.Interop buffer, int bufferIndex, @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { assert JSArrayBuffer.isJSInteropArrayBuffer(buffer) && !JSArrayBuffer.isJSDirectOrSharedArrayBuffer(buffer) : buffer; CompilerAsserts.partialEvaluationConstant(factory); - TypedArray strategy = factory.createArrayType(false, true, false, true); + TypedArray strategy = factory.createArrayType(TypedArray.BUFFER_TYPE_INTEROP, true, false); CompilerAsserts.partialEvaluationConstant(strategy); strategy.setBufferElement(buffer, bufferIndex, littleEndian, value, interop); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/JSConstructTypedArrayNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/JSConstructTypedArrayNode.java index 495e0429e44..4410eddd805 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/JSConstructTypedArrayNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/JSConstructTypedArrayNode.java @@ -40,6 +40,11 @@ */ package com.oracle.truffle.js.builtins; +import static com.oracle.truffle.js.runtime.array.TypedArray.BUFFER_TYPE_ARRAY; +import static com.oracle.truffle.js.runtime.array.TypedArray.BUFFER_TYPE_DIRECT; +import static com.oracle.truffle.js.runtime.array.TypedArray.BUFFER_TYPE_INTEROP; +import static com.oracle.truffle.js.runtime.array.TypedArray.BUFFER_TYPE_SHARED; + import java.nio.ByteBuffer; import java.util.NoSuchElementException; @@ -181,19 +186,18 @@ private void checkDetachedBuffer(JSArrayBufferObject buffer) { protected JSDynamicObject doArrayBuffer(JSDynamicObject newTarget, JSArrayBufferObject arrayBuffer, Object byteOffset0, Object length0, @Cached @Shared InlinedConditionProfile lengthIsUndefined) { checkDetachedBuffer(arrayBuffer); - return doArrayBufferImpl(arrayBuffer, byteOffset0, length0, newTarget, false, false, this, lengthIsUndefined); + return doArrayBufferImpl(arrayBuffer, byteOffset0, length0, newTarget, BUFFER_TYPE_ARRAY, this, lengthIsUndefined); } @Specialization(guards = {"!isUndefined(newTarget)", "isJSDirectArrayBuffer(arrayBuffer)"}) protected JSDynamicObject doDirectArrayBuffer(JSDynamicObject newTarget, JSArrayBufferObject arrayBuffer, Object byteOffset0, Object length0, @Cached @Shared InlinedConditionProfile lengthIsUndefined) { checkDetachedBuffer(arrayBuffer); - return doArrayBufferImpl(arrayBuffer, byteOffset0, length0, newTarget, true, false, this, lengthIsUndefined); + return doArrayBufferImpl(arrayBuffer, byteOffset0, length0, newTarget, BUFFER_TYPE_DIRECT, this, lengthIsUndefined); } private JSDynamicObject doArrayBufferImpl(JSArrayBufferObject arrayBuffer, Object byteOffset0, Object length0, JSDynamicObject newTarget, - boolean direct, boolean isInteropBuffer, - Node node, InlinedConditionProfile lengthIsUndefinedProfile) { + byte bufferType, Node node, InlinedConditionProfile lengthIsUndefinedProfile) { final int elementSize = factory.getBytesPerElement(); final long byteOffset = toIndex(byteOffset0); @@ -227,7 +231,7 @@ private JSDynamicObject doArrayBufferImpl(JSArrayBufferObject arrayBuffer, Objec } assert byteOffset <= Integer.MAX_VALUE && length <= Integer.MAX_VALUE; - TypedArray typedArray = factory.createArrayType(direct, byteOffset != 0, length != JSArrayBufferViewBase.AUTO_LENGTH, isInteropBuffer); + TypedArray typedArray = factory.createArrayType(bufferType, byteOffset != 0, length != JSArrayBufferViewBase.AUTO_LENGTH); return createTypedArray(arrayBuffer, typedArray, (int) byteOffset, (int) length, newTarget); } @@ -242,7 +246,7 @@ private JSDynamicObject doArrayBufferImpl(JSArrayBufferObject arrayBuffer, Objec @Specialization(guards = {"!isUndefined(newTarget)", "isJSSharedArrayBuffer(arrayBuffer)"}) protected JSDynamicObject doSharedArrayBuffer(JSDynamicObject newTarget, JSArrayBufferObject arrayBuffer, Object byteOffset0, Object length0, @Cached @Shared InlinedConditionProfile lengthIsUndefined) { - return doDirectArrayBuffer(newTarget, arrayBuffer, byteOffset0, length0, lengthIsUndefined); + return doArrayBufferImpl(arrayBuffer, byteOffset0, length0, newTarget, BUFFER_TYPE_SHARED, this, lengthIsUndefined); } /** @@ -256,7 +260,7 @@ protected JSDynamicObject doSharedArrayBuffer(JSDynamicObject newTarget, JSArray @Specialization(guards = {"!isUndefined(newTarget)", "isJSInteropArrayBuffer(arrayBuffer)"}) protected JSDynamicObject doInteropArrayBuffer(JSDynamicObject newTarget, JSArrayBufferObject arrayBuffer, Object byteOffset0, Object length0, @Cached @Shared InlinedConditionProfile lengthIsUndefined) { - return doArrayBufferImpl(arrayBuffer, byteOffset0, length0, newTarget, false, true, this, lengthIsUndefined); + return doArrayBufferImpl(arrayBuffer, byteOffset0, length0, newTarget, BUFFER_TYPE_INTEROP, this, lengthIsUndefined); } /** @@ -282,7 +286,7 @@ protected JSDynamicObject doTypedArray(JSDynamicObject newTarget, JSTypedArrayOb throw Errors.createTypeErrorCannotMixBigIntWithOtherTypes(this); } - TypedArray typedArray = factory.createArrayType(getContext().isOptionDirectByteBuffer(), false, true); + TypedArray typedArray = factory.createArrayType(getContext().isOptionDirectByteBuffer() ? BUFFER_TYPE_DIRECT : BUFFER_TYPE_ARRAY, false, true); JSDynamicObject result = createTypedArray(arrayBuffer, typedArray, 0, (int) length, newTarget); assert typedArray == JSArrayBufferView.typedArrayGetArrayType(result); @@ -375,7 +379,7 @@ protected JSDynamicObject doObject(JSDynamicObject newTarget, JSObject object, @ SimpleArrayList values = iterableToListNode.execute(getIteratorFromMethodNode.execute(node, object, usingIterator)); int len = values.size(); JSArrayBufferObject arrayBuffer = createTypedArrayBuffer(len); - TypedArray typedArray = factory.createArrayType(getContext().isOptionDirectByteBuffer(), false, true); + TypedArray typedArray = factory.createArrayType(getContext().isOptionDirectByteBuffer() ? BUFFER_TYPE_DIRECT : BUFFER_TYPE_ARRAY, false, true); JSDynamicObject obj = integerIndexedObjectCreate(arrayBuffer, typedArray, 0, len, proto); for (int k = 0; k < len; k++) { Object kValue = values.get(k); @@ -388,7 +392,7 @@ protected JSDynamicObject doObject(JSDynamicObject newTarget, JSObject object, @ long len = getLengthNode.executeLong(object); JSArrayBufferObject arrayBuffer = createTypedArrayBuffer(len); assert len <= Integer.MAX_VALUE; - TypedArray typedArray = factory.createArrayType(getContext().isOptionDirectByteBuffer(), false, true); + TypedArray typedArray = factory.createArrayType(getContext().isOptionDirectByteBuffer() ? BUFFER_TYPE_DIRECT : BUFFER_TYPE_ARRAY, false, true); JSDynamicObject obj = integerIndexedObjectCreate(arrayBuffer, typedArray, 0, (int) len, proto); for (int k = 0; k < len; k++) { Object kValue = readNode.executeWithTargetAndIndex(object, k); @@ -409,7 +413,7 @@ protected JSDynamicObject doForeignObject(JSDynamicObject newTarget, Object obje if (interop.hasBufferElements(object)) { JSArrayBufferObject arrayBuffer = JSArrayBuffer.createInteropArrayBuffer(getContext(), getRealm(), object); checkLengthLimit(arrayBuffer.getByteLength(), 1); - return doArrayBufferImpl(arrayBuffer, byteOffset0, length0, newTarget, false, true, node, lengthIsUndefined); + return doArrayBufferImpl(arrayBuffer, byteOffset0, length0, newTarget, BUFFER_TYPE_INTEROP, node, lengthIsUndefined); } long length; @@ -482,7 +486,7 @@ private JSArrayBufferObject createTypedArrayBuffer(long length) { */ private JSDynamicObject createTypedArrayWithLength(long length, JSDynamicObject newTarget) { JSArrayBufferObject arrayBuffer = createTypedArrayBuffer(length); - TypedArray typedArray = factory.createArrayType(getContext().isOptionDirectByteBuffer(), false, true); + TypedArray typedArray = factory.createArrayType(getContext().isOptionDirectByteBuffer() ? BUFFER_TYPE_DIRECT : BUFFER_TYPE_ARRAY, false, true); return createTypedArray(arrayBuffer, typedArray, 0, (int) length, newTarget); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java index dc773ff2ef6..fb84941c821 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java @@ -40,6 +40,9 @@ */ package com.oracle.truffle.js.builtins; +import static com.oracle.truffle.js.runtime.array.TypedArray.BUFFER_TYPE_ARRAY; +import static com.oracle.truffle.js.runtime.array.TypedArray.BUFFER_TYPE_DIRECT; +import static com.oracle.truffle.js.runtime.array.TypedArray.BUFFER_TYPE_INTEROP; import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arrayGetArrayType; import static com.oracle.truffle.js.runtime.builtins.JSArrayBufferView.typedArrayGetArrayType; @@ -536,7 +539,7 @@ private void setArrayBufferView(JSTypedArrayObject targetView, JSTypedArrayObjec sourceBuffer = cloneArrayBuffer(sourceBuffer, sourceArray, srcByteLength, srcByteOffset); if (sourceArray.isInterop()) { // cloned buffer is not an interop buffer anymore - sourceArray = sourceArray.getFactory().createArrayType(getContext().isOptionDirectByteBuffer(), false, true); + sourceArray = sourceArray.getFactory().createArrayType(getContext().isOptionDirectByteBuffer() ? BUFFER_TYPE_DIRECT : BUFFER_TYPE_ARRAY, false, true); } srcByteIndex = 0; } @@ -693,8 +696,8 @@ private JSArrayBufferObject cloneArrayBuffer(JSArrayBufferObject sourceBuffer, T private JSArrayBufferObject cloneInteropArrayBuffer(JSArrayBufferObject sourceBuffer, int srcByteLength, int srcByteOffset, InteropLibrary interop) { assert JSArrayBuffer.isJSInteropArrayBuffer(sourceBuffer); boolean direct = getContext().isOptionDirectByteBuffer(); - TypedArray sourceType = TypedArrayFactory.Int8Array.createArrayType(false, false, true, true); - TypedArray clonedType = TypedArrayFactory.Int8Array.createArrayType(direct, false, true); + TypedArray sourceType = TypedArrayFactory.Int8Array.createArrayType(BUFFER_TYPE_INTEROP, false, true); + TypedArray clonedType = TypedArrayFactory.Int8Array.createArrayType(direct ? BUFFER_TYPE_DIRECT : BUFFER_TYPE_ARRAY, false, true); JSArrayBufferObject clonedArrayBuffer = direct ? JSArrayBuffer.createDirectArrayBuffer(getContext(), getRealm(), srcByteLength) : JSArrayBuffer.createArrayBuffer(getContext(), getRealm(), srcByteLength); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/wasm/ExportByteSourceNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/wasm/ExportByteSourceNode.java index cf498812569..94d8fbaa82e 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/wasm/ExportByteSourceNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/wasm/ExportByteSourceNode.java @@ -115,9 +115,17 @@ private Object exportBuffer(JSArrayBufferObject arrayBuffer, int offset, int len buffer = JSArrayBuffer.createArrayBuffer(context, realm, 0); } // Wrap ArrayBuffer into Uint8Array - to allow reading its bytes on WASM side - boolean interop = JSArrayBuffer.isJSInteropArrayBuffer(arrayBuffer); - boolean direct = JSArrayBuffer.isJSDirectArrayBuffer(arrayBuffer); - TypedArray arrayType = TypedArrayFactory.Uint8Array.createArrayType(direct, (offset != 0), true, interop); + byte bufferType; + if (JSArrayBuffer.isJSInteropArrayBuffer(arrayBuffer)) { + bufferType = TypedArray.BUFFER_TYPE_INTEROP; + } else if (JSArrayBuffer.isJSHeapArrayBuffer(arrayBuffer)) { + bufferType = TypedArray.BUFFER_TYPE_ARRAY; + } else if (JSArrayBuffer.isJSDirectArrayBuffer(arrayBuffer)) { + bufferType = TypedArray.BUFFER_TYPE_DIRECT; + } else { + bufferType = TypedArray.BUFFER_TYPE_SHARED; + } + TypedArray arrayType = TypedArrayFactory.Uint8Array.createArrayType(bufferType, (offset != 0), true); return JSArrayBufferView.createArrayBufferView(context, realm, buffer, arrayType, offset, length); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArray.java index 679b1ef2eb6..5145ab198ea 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArray.java @@ -91,9 +91,10 @@ public enum ElementType { private final TruffleString name; private final TypedArrayFactory factory; - protected static final byte BUFFER_TYPE_ARRAY = 0; - protected static final byte BUFFER_TYPE_DIRECT = 1; - protected static final byte BUFFER_TYPE_INTEROP = -1; + public static final byte BUFFER_TYPE_ARRAY = 0; + public static final byte BUFFER_TYPE_DIRECT = 1; + public static final byte BUFFER_TYPE_SHARED = 2; + public static final byte BUFFER_TYPE_INTEROP = -1; protected TypedArray(TypedArrayFactory factory, boolean offset, boolean fixedLength, byte bufferType) { this.bytesPerElement = factory.getBytesPerElement(); @@ -117,9 +118,10 @@ public final int lengthInt(JSDynamicObject object) { } else { JSArrayBufferObject arrayBuffer = typedArray.getArrayBuffer(); int byteLength = switch (bufferType) { - case BUFFER_TYPE_ARRAY -> ((JSArrayBufferObject.Heap) arrayBuffer).getByteLength(); - case BUFFER_TYPE_DIRECT -> ((JSArrayBufferObject.DirectBase) arrayBuffer).getByteLength(); case BUFFER_TYPE_INTEROP -> ((JSArrayBufferObject.Interop) arrayBuffer).getByteLength(); + case BUFFER_TYPE_ARRAY -> ((JSArrayBufferObject.Heap) arrayBuffer).getByteLength(); + case BUFFER_TYPE_DIRECT -> ((JSArrayBufferObject.Direct) arrayBuffer).getByteLength(); + case BUFFER_TYPE_SHARED -> ((JSArrayBufferObject.Shared) arrayBuffer).getByteLength(); default -> throw Errors.shouldNotReachHereUnexpectedValue(bufferType); }; return (byteLength - getOffset(object)) / bytesPerElement; @@ -428,8 +430,8 @@ public ElementType getElementType() { } public static final class DirectInt8Array extends TypedIntArray { - DirectInt8Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { - super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); + DirectInt8Array(TypedArrayFactory factory, boolean shared, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, shared ? BUFFER_TYPE_SHARED : BUFFER_TYPE_DIRECT); } @Override @@ -561,8 +563,8 @@ public ElementType getElementType() { } public static final class DirectUint8Array extends TypedIntArray { - DirectUint8Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { - super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); + DirectUint8Array(TypedArrayFactory factory, boolean shared, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, shared ? BUFFER_TYPE_SHARED : BUFFER_TYPE_DIRECT); } @Override @@ -683,8 +685,8 @@ public void setBufferElementIntImpl(JSArrayBufferObject buffer, int index, boole } public static final class DirectUint8ClampedArray extends AbstractUint8ClampedArray { - DirectUint8ClampedArray(TypedArrayFactory factory, boolean offset, boolean fixedLength) { - super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); + DirectUint8ClampedArray(TypedArrayFactory factory, boolean shared, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, shared ? BUFFER_TYPE_SHARED : BUFFER_TYPE_DIRECT); } @Override @@ -768,8 +770,8 @@ public ElementType getElementType() { } public static final class DirectInt16Array extends TypedIntArray { - DirectInt16Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { - super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); + DirectInt16Array(TypedArrayFactory factory, boolean shared, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, shared ? BUFFER_TYPE_SHARED : BUFFER_TYPE_DIRECT); } @Override @@ -901,8 +903,8 @@ public ElementType getElementType() { } public static final class DirectUint16Array extends TypedIntArray { - DirectUint16Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { - super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); + DirectUint16Array(TypedArrayFactory factory, boolean shared, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, shared ? BUFFER_TYPE_SHARED : BUFFER_TYPE_DIRECT); } @Override @@ -998,8 +1000,8 @@ public ElementType getElementType() { } public static final class DirectInt32Array extends TypedIntArray { - DirectInt32Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { - super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); + DirectInt32Array(TypedArrayFactory factory, boolean shared, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, shared ? BUFFER_TYPE_SHARED : BUFFER_TYPE_DIRECT); } @Override @@ -1155,8 +1157,8 @@ public void setBufferElementIntImpl(JSArrayBufferObject buffer, int index, boole } public static final class DirectUint32Array extends AbstractUint32Array { - DirectUint32Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { - super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); + DirectUint32Array(TypedArrayFactory factory, boolean shared, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, shared ? BUFFER_TYPE_SHARED : BUFFER_TYPE_DIRECT); } @Override @@ -1324,8 +1326,8 @@ public ElementType getElementType() { } public static final class DirectBigInt64Array extends TypedBigIntArray { - DirectBigInt64Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { - super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); + DirectBigInt64Array(TypedArrayFactory factory, boolean shared, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, shared ? BUFFER_TYPE_SHARED : BUFFER_TYPE_DIRECT); } @Override @@ -1466,8 +1468,8 @@ public ElementType getElementType() { } public static final class DirectBigUint64Array extends TypedBigIntArray { - DirectBigUint64Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { - super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); + DirectBigUint64Array(TypedArrayFactory factory, boolean shared, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, shared ? BUFFER_TYPE_SHARED : BUFFER_TYPE_DIRECT); } @Override @@ -1613,8 +1615,8 @@ public ElementType getElementType() { } public static final class DirectFloat16Array extends TypedFloatArray { - DirectFloat16Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { - super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); + DirectFloat16Array(TypedArrayFactory factory, boolean shared, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, shared ? BUFFER_TYPE_SHARED : BUFFER_TYPE_DIRECT); } @Override @@ -1728,8 +1730,8 @@ public ElementType getElementType() { } public static final class DirectFloat32Array extends TypedFloatArray { - DirectFloat32Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { - super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); + DirectFloat32Array(TypedArrayFactory factory, boolean shared, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, shared ? BUFFER_TYPE_SHARED : BUFFER_TYPE_DIRECT); } @Override @@ -1843,8 +1845,8 @@ public ElementType getElementType() { } public static final class DirectFloat64Array extends TypedFloatArray { - DirectFloat64Array(TypedArrayFactory factory, boolean offset, boolean fixedLength) { - super(factory, offset, fixedLength, BUFFER_TYPE_DIRECT); + DirectFloat64Array(TypedArrayFactory factory, boolean shared, boolean offset, boolean fixedLength) { + super(factory, offset, fixedLength, shared ? BUFFER_TYPE_SHARED : BUFFER_TYPE_DIRECT); } @Override diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArrayFactory.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArrayFactory.java index fa02e65cc77..50c1c850145 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArrayFactory.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArrayFactory.java @@ -40,9 +40,15 @@ */ package com.oracle.truffle.js.runtime.array; +import static com.oracle.truffle.js.runtime.array.TypedArray.BUFFER_TYPE_ARRAY; +import static com.oracle.truffle.js.runtime.array.TypedArray.BUFFER_TYPE_DIRECT; +import static com.oracle.truffle.js.runtime.array.TypedArray.BUFFER_TYPE_INTEROP; +import static com.oracle.truffle.js.runtime.array.TypedArray.BUFFER_TYPE_SHARED; + import java.util.Arrays; import com.oracle.truffle.api.strings.TruffleString; +import com.oracle.truffle.js.runtime.Errors; import com.oracle.truffle.js.runtime.JSRealm; import com.oracle.truffle.js.runtime.Strings; import com.oracle.truffle.js.runtime.array.TypedArray.BigInt64Array; @@ -88,145 +94,145 @@ public enum TypedArrayFactory implements PrototypeSupplier { Int8Array(TypedArray.INT8_BYTES_PER_ELEMENT) { @Override TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { - if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropInt8Array(this, offset, fixedLength); - } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectInt8Array(this, offset, fixedLength); - } else { - return new Int8Array(this, offset, fixedLength); - } + return switch (bufferType) { + case BUFFER_TYPE_INTEROP -> new InteropInt8Array(this, offset, fixedLength); + case BUFFER_TYPE_ARRAY -> new Int8Array(this, offset, fixedLength); + case BUFFER_TYPE_DIRECT -> new DirectInt8Array(this, false, offset, fixedLength); + case BUFFER_TYPE_SHARED -> new DirectInt8Array(this, true, offset, fixedLength); + default -> throw Errors.shouldNotReachHereUnexpectedValue(bufferType); + }; } }, Uint8Array(TypedArray.UINT8_BYTES_PER_ELEMENT) { @Override TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { - if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropUint8Array(this, offset, fixedLength); - } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectUint8Array(this, offset, fixedLength); - } else { - return new Uint8Array(this, offset, fixedLength); - } + return switch (bufferType) { + case BUFFER_TYPE_INTEROP -> new InteropUint8Array(this, offset, fixedLength); + case BUFFER_TYPE_ARRAY -> new Uint8Array(this, offset, fixedLength); + case BUFFER_TYPE_DIRECT -> new DirectUint8Array(this, false, offset, fixedLength); + case BUFFER_TYPE_SHARED -> new DirectUint8Array(this, true, offset, fixedLength); + default -> throw Errors.shouldNotReachHereUnexpectedValue(bufferType); + }; } }, Uint8ClampedArray(TypedArray.UINT8_BYTES_PER_ELEMENT) { @Override TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { - if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropUint8ClampedArray(this, offset, fixedLength); - } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectUint8ClampedArray(this, offset, fixedLength); - } else { - return new Uint8ClampedArray(this, offset, fixedLength); - } + return switch (bufferType) { + case BUFFER_TYPE_INTEROP -> new InteropUint8ClampedArray(this, offset, fixedLength); + case BUFFER_TYPE_ARRAY -> new Uint8ClampedArray(this, offset, fixedLength); + case BUFFER_TYPE_DIRECT -> new DirectUint8ClampedArray(this, false, offset, fixedLength); + case BUFFER_TYPE_SHARED -> new DirectUint8ClampedArray(this, true, offset, fixedLength); + default -> throw Errors.shouldNotReachHereUnexpectedValue(bufferType); + }; } }, Int16Array(TypedArray.INT16_BYTES_PER_ELEMENT) { @Override TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { - if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropInt16Array(this, offset, fixedLength); - } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectInt16Array(this, offset, fixedLength); - } else { - return new Int16Array(this, offset, fixedLength); - } + return switch (bufferType) { + case BUFFER_TYPE_INTEROP -> new InteropInt16Array(this, offset, fixedLength); + case BUFFER_TYPE_ARRAY -> new Int16Array(this, offset, fixedLength); + case BUFFER_TYPE_DIRECT -> new DirectInt16Array(this, false, offset, fixedLength); + case BUFFER_TYPE_SHARED -> new DirectInt16Array(this, true, offset, fixedLength); + default -> throw Errors.shouldNotReachHereUnexpectedValue(bufferType); + }; } }, Uint16Array(TypedArray.UINT16_BYTES_PER_ELEMENT) { @Override TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { - if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropUint16Array(this, offset, fixedLength); - } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectUint16Array(this, offset, fixedLength); - } else { - return new Uint16Array(this, offset, fixedLength); - } + return switch (bufferType) { + case BUFFER_TYPE_INTEROP -> new InteropUint16Array(this, offset, fixedLength); + case BUFFER_TYPE_ARRAY -> new Uint16Array(this, offset, fixedLength); + case BUFFER_TYPE_DIRECT -> new DirectUint16Array(this, false, offset, fixedLength); + case BUFFER_TYPE_SHARED -> new DirectUint16Array(this, true, offset, fixedLength); + default -> throw Errors.shouldNotReachHereUnexpectedValue(bufferType); + }; } }, Int32Array(TypedArray.INT32_BYTES_PER_ELEMENT) { @Override TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { - if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropInt32Array(this, offset, fixedLength); - } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectInt32Array(this, offset, fixedLength); - } else { - return new Int32Array(this, offset, fixedLength); - } + return switch (bufferType) { + case BUFFER_TYPE_INTEROP -> new InteropInt32Array(this, offset, fixedLength); + case BUFFER_TYPE_ARRAY -> new Int32Array(this, offset, fixedLength); + case BUFFER_TYPE_DIRECT -> new DirectInt32Array(this, false, offset, fixedLength); + case BUFFER_TYPE_SHARED -> new DirectInt32Array(this, true, offset, fixedLength); + default -> throw Errors.shouldNotReachHereUnexpectedValue(bufferType); + }; } }, Uint32Array(TypedArray.UINT32_BYTES_PER_ELEMENT) { @Override TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { - if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropUint32Array(this, offset, fixedLength); - } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectUint32Array(this, offset, fixedLength); - } else { - return new Uint32Array(this, offset, fixedLength); - } + return switch (bufferType) { + case BUFFER_TYPE_INTEROP -> new InteropUint32Array(this, offset, fixedLength); + case BUFFER_TYPE_ARRAY -> new Uint32Array(this, offset, fixedLength); + case BUFFER_TYPE_DIRECT -> new DirectUint32Array(this, false, offset, fixedLength); + case BUFFER_TYPE_SHARED -> new DirectUint32Array(this, true, offset, fixedLength); + default -> throw Errors.shouldNotReachHereUnexpectedValue(bufferType); + }; } }, Float32Array(TypedArray.FLOAT32_BYTES_PER_ELEMENT) { @Override TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { - if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropFloat32Array(this, offset, fixedLength); - } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectFloat32Array(this, offset, fixedLength); - } else { - return new Float32Array(this, offset, fixedLength); - } + return switch (bufferType) { + case BUFFER_TYPE_INTEROP -> new InteropFloat32Array(this, offset, fixedLength); + case BUFFER_TYPE_ARRAY -> new Float32Array(this, offset, fixedLength); + case BUFFER_TYPE_DIRECT -> new DirectFloat32Array(this, false, offset, fixedLength); + case BUFFER_TYPE_SHARED -> new DirectFloat32Array(this, true, offset, fixedLength); + default -> throw Errors.shouldNotReachHereUnexpectedValue(bufferType); + }; } }, Float64Array(TypedArray.FLOAT64_BYTES_PER_ELEMENT) { @Override TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { - if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropFloat64Array(this, offset, fixedLength); - } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectFloat64Array(this, offset, fixedLength); - } else { - return new Float64Array(this, offset, fixedLength); - } + return switch (bufferType) { + case BUFFER_TYPE_INTEROP -> new InteropFloat64Array(this, offset, fixedLength); + case BUFFER_TYPE_ARRAY -> new Float64Array(this, offset, fixedLength); + case BUFFER_TYPE_DIRECT -> new DirectFloat64Array(this, false, offset, fixedLength); + case BUFFER_TYPE_SHARED -> new DirectFloat64Array(this, true, offset, fixedLength); + default -> throw Errors.shouldNotReachHereUnexpectedValue(bufferType); + }; } }, BigInt64Array(TypedArray.BIGINT64_BYTES_PER_ELEMENT) { @Override TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { - if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropBigInt64Array(this, offset, fixedLength); - } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectBigInt64Array(this, offset, fixedLength); - } else { - return new BigInt64Array(this, offset, fixedLength); - } + return switch (bufferType) { + case BUFFER_TYPE_INTEROP -> new InteropBigInt64Array(this, offset, fixedLength); + case BUFFER_TYPE_ARRAY -> new BigInt64Array(this, offset, fixedLength); + case BUFFER_TYPE_DIRECT -> new DirectBigInt64Array(this, false, offset, fixedLength); + case BUFFER_TYPE_SHARED -> new DirectBigInt64Array(this, true, offset, fixedLength); + default -> throw Errors.shouldNotReachHereUnexpectedValue(bufferType); + }; } }, BigUint64Array(TypedArray.BIGUINT64_BYTES_PER_ELEMENT) { @Override TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { - if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropBigUint64Array(this, offset, fixedLength); - } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectBigUint64Array(this, offset, fixedLength); - } else { - return new BigUint64Array(this, offset, fixedLength); - } + return switch (bufferType) { + case BUFFER_TYPE_INTEROP -> new InteropBigUint64Array(this, offset, fixedLength); + case BUFFER_TYPE_ARRAY -> new BigUint64Array(this, offset, fixedLength); + case BUFFER_TYPE_DIRECT -> new DirectBigUint64Array(this, false, offset, fixedLength); + case BUFFER_TYPE_SHARED -> new DirectBigUint64Array(this, true, offset, fixedLength); + default -> throw Errors.shouldNotReachHereUnexpectedValue(bufferType); + }; } }, Float16Array(TypedArray.FLOAT16_BYTES_PER_ELEMENT) { @Override TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLength) { - if (bufferType == TypedArray.BUFFER_TYPE_INTEROP) { - return new InteropFloat16Array(this, offset, fixedLength); - } else if (bufferType == TypedArray.BUFFER_TYPE_DIRECT) { - return new DirectFloat16Array(this, offset, fixedLength); - } else { - return new Float16Array(this, offset, fixedLength); - } + return switch (bufferType) { + case BUFFER_TYPE_INTEROP -> new InteropFloat16Array(this, offset, fixedLength); + case BUFFER_TYPE_ARRAY -> new Float16Array(this, offset, fixedLength); + case BUFFER_TYPE_DIRECT -> new DirectFloat16Array(this, false, offset, fixedLength); + case BUFFER_TYPE_SHARED -> new DirectFloat16Array(this, true, offset, fixedLength); + default -> throw Errors.shouldNotReachHereUnexpectedValue(bufferType); + }; } }; @@ -240,6 +246,10 @@ TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLe private final TypedArray directArrayTypeWithOffset; private final TypedArray directArrayTypeAutoLength; private final TypedArray directArrayTypeWithOffsetAutoLength; + private final TypedArray sharedArrayType; + private final TypedArray sharedArrayTypeWithOffset; + private final TypedArray sharedArrayTypeAutoLength; + private final TypedArray sharedArrayTypeWithOffsetAutoLength; private final TypedArray interopArrayType; private final TypedArray interopArrayTypeWithOffset; private final TypedArray interopArrayTypeAutoLength; @@ -256,6 +266,10 @@ TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLe this.directArrayTypeWithOffset = instantiateArrayType(TypedArray.BUFFER_TYPE_DIRECT, true, true); this.directArrayTypeAutoLength = instantiateArrayType(TypedArray.BUFFER_TYPE_DIRECT, false, false); this.directArrayTypeWithOffsetAutoLength = instantiateArrayType(TypedArray.BUFFER_TYPE_DIRECT, true, false); + this.sharedArrayType = instantiateArrayType(TypedArray.BUFFER_TYPE_SHARED, false, true); + this.sharedArrayTypeWithOffset = instantiateArrayType(TypedArray.BUFFER_TYPE_SHARED, true, true); + this.sharedArrayTypeAutoLength = instantiateArrayType(TypedArray.BUFFER_TYPE_SHARED, false, false); + this.sharedArrayTypeWithOffsetAutoLength = instantiateArrayType(TypedArray.BUFFER_TYPE_SHARED, true, false); this.interopArrayType = instantiateArrayType(TypedArray.BUFFER_TYPE_INTEROP, false, true); this.interopArrayTypeWithOffset = instantiateArrayType(TypedArray.BUFFER_TYPE_INTEROP, true, true); this.interopArrayTypeAutoLength = instantiateArrayType(TypedArray.BUFFER_TYPE_INTEROP, false, false); @@ -266,30 +280,22 @@ TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLe !interopArrayType.hasOffset() && interopArrayTypeWithOffset.hasOffset() && interopArrayType.isInterop() && interopArrayTypeWithOffset.isInterop(); } - public final TypedArray createArrayType(boolean direct, boolean offset, boolean fixedLength) { - return createArrayType(direct, offset, fixedLength, false); - } - - public final TypedArray createArrayType(boolean direct, boolean offset, boolean fixedLength, boolean interop) { - if (interop) { - if (offset) { - return fixedLength ? interopArrayTypeWithOffset : interopArrayTypeWithOffsetAutoLength; - } else { - return fixedLength ? interopArrayType : interopArrayTypeAutoLength; - } - } else if (direct) { - if (offset) { - return fixedLength ? directArrayTypeWithOffset : directArrayTypeWithOffsetAutoLength; - } else { - return fixedLength ? directArrayType : directArrayTypeAutoLength; - } - } else { - if (offset) { - return fixedLength ? arrayTypeWithOffset : arrayTypeWithOffsetAutoLength; - } else { - return fixedLength ? arrayType : arrayTypeAutoLength; - } - } + public final TypedArray createArrayType(byte bufferType, boolean offset, boolean fixedLength) { + return switch (bufferType) { + case BUFFER_TYPE_INTEROP -> offset ? // + (fixedLength ? interopArrayTypeWithOffset : interopArrayTypeWithOffsetAutoLength) : // + (fixedLength ? interopArrayType : interopArrayTypeAutoLength); + case BUFFER_TYPE_ARRAY -> offset ? // + (fixedLength ? arrayTypeWithOffset : arrayTypeWithOffsetAutoLength) : // + (fixedLength ? arrayType : arrayTypeAutoLength); + case BUFFER_TYPE_DIRECT -> offset ? // + (fixedLength ? directArrayTypeWithOffset : directArrayTypeWithOffsetAutoLength) : // + (fixedLength ? directArrayType : directArrayTypeAutoLength); + case BUFFER_TYPE_SHARED -> offset ? // + (fixedLength ? sharedArrayTypeWithOffset : sharedArrayTypeWithOffsetAutoLength) : // + (fixedLength ? sharedArrayType : sharedArrayTypeAutoLength); + default -> throw Errors.shouldNotReachHereUnexpectedValue(bufferType); + }; } public final int getBytesPerElement() { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayBufferView.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayBufferView.java index 3fdabdced67..49df8fc5900 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayBufferView.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayBufferView.java @@ -342,7 +342,7 @@ private static JSObject createLegacyArrayBufferViewPrototype(JSRealm realm, Type byte[] byteArray = new byte[0]; JSObjectFactory bufferFactory = context.getArrayBufferFactory(); JSArrayBufferObject emptyArrayBuffer = bufferFactory.initProto(JSArrayBufferObject.createHeapArrayBuffer(bufferFactory.getShape(realm), bufferFactory.getPrototype(realm), byteArray), realm); - TypedArray arrayType = factory.createArrayType(false, false, true); + TypedArray arrayType = factory.createArrayType(TypedArray.BUFFER_TYPE_ARRAY, false, true); Shape shape = JSShape.createPrototypeShape(context, INSTANCE, taPrototype); JSObject prototype = JSTypedArrayObject.create(shape, taPrototype, arrayType, emptyArrayBuffer, 0, 0); JSObjectUtil.setOrVerifyPrototype(context, prototype, taPrototype); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyMemoryWaitCallback.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyMemoryWaitCallback.java index d5ea7e16e76..67a3b511e8e 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyMemoryWaitCallback.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyMemoryWaitCallback.java @@ -147,14 +147,14 @@ private TruffleString atomicsWait(JSArrayBufferObject buffer, int address, long } private static int doVolatileGetFromBuffer(JSArrayBufferObject buffer, int intArrayOffset) { - TypedArray.TypedIntArray typedArray = (TypedArray.TypedIntArray) TypedArrayFactory.Int32Array.createArrayType(true, false, true, true); + TypedArray.TypedIntArray typedArray = (TypedArray.TypedIntArray) TypedArrayFactory.Int32Array.createArrayType(TypedArray.BUFFER_TYPE_DIRECT, false, true); int result = typedArray.getBufferElementIntImpl(buffer, intArrayOffset, true, InteropLibrary.getUncached()); VarHandle.acquireFence(); return result; } private static BigInt doVolatileGetBigIntFromBuffer(JSArrayBufferObject buffer, int bigIntArrayOffset) { - TypedArray.TypedBigIntArray typedArray = (TypedArray.TypedBigIntArray) TypedArrayFactory.BigInt64Array.createArrayType(true, false, true, true); + TypedArray.TypedBigIntArray typedArray = (TypedArray.TypedBigIntArray) TypedArrayFactory.BigInt64Array.createArrayType(TypedArray.BUFFER_TYPE_DIRECT, false, true); BigInt result = BigInt.valueOf(typedArray.getBufferElementLongImpl(buffer, bigIntArrayOffset, true, InteropLibrary.getUncached())); VarHandle.acquireFence(); return result; diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java index 075419fdf3c..22c43c07388 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java @@ -1485,7 +1485,7 @@ public int typedArrayLength(Object typedArray) { } private Object typedArrayNew(Object arrayBuffer, int offset, int length, TypedArrayFactory factory) { - TypedArray arrayType = factory.createArrayType(true, offset != 0, true); + TypedArray arrayType = factory.createArrayType(TypedArray.BUFFER_TYPE_DIRECT, offset != 0, true); JSArrayBufferObject dynamicObject = (JSArrayBufferObject) arrayBuffer; JSContext context = JSObject.getJSContext(dynamicObject); JSRealm realm = getCurrentRealm(); diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/Deserializer.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/Deserializer.java index 3742a47071e..df571349a2f 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/Deserializer.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/Deserializer.java @@ -462,7 +462,7 @@ private JSDynamicObject readJSArrayBufferView(JSContext context, JSRealm realm, view = JSDataView.createDataView(context, realm, arrayBuffer, offset, byteLength); } else { TypedArrayFactory factory = tag.getFactory(); - TypedArray array = factory.createArrayType(true, offset != 0, true); + TypedArray array = factory.createArrayType(TypedArray.BUFFER_TYPE_DIRECT, offset != 0, true); int length = byteLength / factory.getBytesPerElement(); view = JSArrayBufferView.createArrayBufferView(context, realm, arrayBuffer, array, offset, length); } From 9c91c505dc02b2d122d7200890bb840810078cbc Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Fri, 14 Jun 2024 01:10:57 +0200 Subject: [PATCH 049/265] Add note about js.esm-eval-returns-exports option to changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd02fad6807..75c52223e40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ See [release calendar](https://www.graalvm.org/release-calendar/) for release da * Implemented the [Array.fromAsync](https://github.com/tc39/proposal-array-from-async) proposal. It is available in ECMAScript staging mode (`--js.ecmascript-version=staging`). * Implemented the [Resizable and Growable ArrayBuffers](https://github.com/tc39/proposal-resizablearraybuffer) proposal. * Updated Node.js to version 20.13.1. +* Made option `js.esm-eval-returns-exports` stable and allowed in `SandboxPolicy.UNTRUSTED`. ## Version 24.0.0 * Implemented the [WebAssembly threads](https://github.com/WebAssembly/threads) proposal. From 492b816e948dfe1bf2b2a3f3dce403a3376aa244 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 12 Jun 2024 23:34:57 +0200 Subject: [PATCH 050/265] Update CI overlay. --- ci.jsonnet | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci.jsonnet b/ci.jsonnet index e2b27a5cf04..0f14851d686 100644 --- a/ci.jsonnet +++ b/ci.jsonnet @@ -6,7 +6,7 @@ local graalNodeJs = import 'graal-nodejs/ci.jsonnet'; // Used to run fewer jobs local useOverlay = true, - local overlay = 'ecbe9b07a592111b950bcb2da30a993478a1488a', + local overlay = '8687d6f5e142a8fbcedab5a5d62f2c9b22b681b2', local no_overlay = 'cb733e564850cd37b685fcef6f3c16b59802b22c', From 332447d831867801f0e9977559a6a9c23c4f4e8a Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 13 Jun 2024 22:03:59 +0200 Subject: [PATCH 051/265] Move JMH benchmarks from post-merge to daily. --- graal-js/ci.jsonnet | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/ci.jsonnet b/graal-js/ci.jsonnet index 5a38bfdeaf1..0f406ddff76 100644 --- a/graal-js/ci.jsonnet +++ b/graal-js/ci.jsonnet @@ -174,7 +174,7 @@ local ci = import '../ci.jsonnet'; // Benchmark builds; need to run on a benchmark machine local benchBuilds = generateBuilds([ - graalJs + common.bench + interopJmhBenchmarks + {name: 'interop-jmh'}, + graalJs + common.dailyBench+ interopJmhBenchmarks + {name: 'interop-jmh'}, ], platforms=[common.jdk21 + common.e3]), builds: styleBuilds + testingBuilds + otherBuilds + benchBuilds, From e63189dfdf4176ee04b2f84c6dfc6857e4c20cb2 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Fri, 14 Jun 2024 21:30:34 +0200 Subject: [PATCH 052/265] Unwrap ShortCircuitTargetableNode in InvokeNode.getPropertyKey(). --- .../truffle/js/nodes/function/JSFunctionCallNode.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/function/JSFunctionCallNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/function/JSFunctionCallNode.java index 24fa4afed85..dab887e1a80 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/function/JSFunctionCallNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/function/JSFunctionCallNode.java @@ -75,11 +75,13 @@ import com.oracle.truffle.api.profiles.ValueProfile; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.nodes.JSGuards; +import com.oracle.truffle.js.nodes.JSNodeUtil; import com.oracle.truffle.js.nodes.JavaScriptBaseNode; import com.oracle.truffle.js.nodes.JavaScriptNode; import com.oracle.truffle.js.nodes.access.JSConstantNode.JSConstantUndefinedNode; import com.oracle.truffle.js.nodes.access.JSProxyCallNode; import com.oracle.truffle.js.nodes.access.JSTargetableNode; +import com.oracle.truffle.js.nodes.access.OptionalChainNode.ShortCircuitTargetableNode; import com.oracle.truffle.js.nodes.access.PropertyGetNode; import com.oracle.truffle.js.nodes.access.PropertyNode; import com.oracle.truffle.js.nodes.access.SuperPropertyReferenceNode; @@ -768,9 +770,9 @@ private JSTargetableNode getFunctionTargetDelegate() { @Override protected Object getPropertyKey() { - JavaScriptNode propertyNode = functionTargetNode; - if (propertyNode instanceof WrapperNode) { - propertyNode = (JavaScriptNode) ((WrapperNode) propertyNode).getDelegateNode(); + JavaScriptNode propertyNode = JSNodeUtil.getWrappedNode(functionTargetNode); + if (propertyNode instanceof ShortCircuitTargetableNode shortCircuitNode) { + propertyNode = JSNodeUtil.getWrappedNode(shortCircuitNode.getExpressionNode()); } if (propertyNode instanceof PropertyNode) { return ((PropertyNode) propertyNode).getPropertyKey(); From 682097c99d8057dd334492a3ebcf61c489569a03 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Fri, 14 Jun 2024 21:38:28 +0200 Subject: [PATCH 053/265] Optional invocation of ForeignInvokeNode should not throw TypeError when there is no valid function. --- .../oracle/truffle/js/nodes/access/OptionalChainNode.java | 8 ++++++-- .../truffle/js/nodes/function/JSFunctionCallNode.java | 6 ++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/OptionalChainNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/OptionalChainNode.java index e65410215a9..ae59d7ff326 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/OptionalChainNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/OptionalChainNode.java @@ -241,6 +241,10 @@ private boolean isNullish(Object targetValue) { return isNullish.profile(isNullOrUndefinedNode.executeBoolean(targetValue)); } + public JSTargetableNode getExpressionNode() { + return expressionNode; + } + @Override public JavaScriptNode getTarget() { return expressionNode.getTarget(); @@ -279,14 +283,14 @@ protected JavaScriptNode copyUninitialized(Set> materialize } @SuppressWarnings("serial") - private static final class ShortCircuitException extends ControlFlowException { + public static final class ShortCircuitException extends ControlFlowException { private static final ShortCircuitException INSTANCE = new ShortCircuitException(); private ShortCircuitException() { } - static ShortCircuitException instance() { + public static ShortCircuitException instance() { return INSTANCE; } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/function/JSFunctionCallNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/function/JSFunctionCallNode.java index dab887e1a80..f9d99db5c0e 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/function/JSFunctionCallNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/function/JSFunctionCallNode.java @@ -81,6 +81,7 @@ import com.oracle.truffle.js.nodes.access.JSConstantNode.JSConstantUndefinedNode; import com.oracle.truffle.js.nodes.access.JSProxyCallNode; import com.oracle.truffle.js.nodes.access.JSTargetableNode; +import com.oracle.truffle.js.nodes.access.OptionalChainNode.ShortCircuitException; import com.oracle.truffle.js.nodes.access.OptionalChainNode.ShortCircuitTargetableNode; import com.oracle.truffle.js.nodes.access.PropertyGetNode; import com.oracle.truffle.js.nodes.access.PropertyNode; @@ -1596,6 +1597,11 @@ private Object fallback(Object receiver, Object[] arguments, Object[] callArgume } } errorBranch.enter(); + // There is no valid function to invoke. Do not throw if the invocation + // is optional, short-circuit instead. + if (getParent() instanceof InvokeNode invokeNode && invokeNode.getFunctionTargetDelegate() instanceof ShortCircuitTargetableNode) { + throw ShortCircuitException.instance(); + } throw Errors.createTypeErrorInteropException(receiver, ex != null ? ex : UnknownIdentifierException.create(Strings.toJavaString(functionName)), "invokeMember", functionName, this); } From 691beda407d8a21952d1c16151ae7d5b3149f896 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Fri, 14 Jun 2024 22:46:55 +0200 Subject: [PATCH 054/265] Regression test of the optional invocation of a foreign function. --- .../com.oracle.truffle.js.test/js/GR-54723.js | 14 ++++ .../truffle/js/test/regress/GR54723.java | 75 +++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 graal-js/src/com.oracle.truffle.js.test/js/GR-54723.js create mode 100644 graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR54723.java diff --git a/graal-js/src/com.oracle.truffle.js.test/js/GR-54723.js b/graal-js/src/com.oracle.truffle.js.test/js/GR-54723.js new file mode 100644 index 00000000000..537156808cf --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/js/GR-54723.js @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ + +load("assert.js"); + +var time = java.lang.System.currentTimeMillis?.(); +assertSame('number', typeof time); + +var result = java.lang.System.iDontExist?.(); +assertSame('undefined', typeof result); diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR54723.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR54723.java new file mode 100644 index 00000000000..fe43975395a --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR54723.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.test.regress; + +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import java.util.Map; + +import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.Value; +import org.graalvm.polyglot.proxy.ProxyExecutable; +import org.graalvm.polyglot.proxy.ProxyObject; +import org.junit.Test; + +import com.oracle.truffle.js.test.JSTest; + +public class GR54723 { + + @Test + public void testIt() { + try (Context ctx = JSTest.newContextBuilder().build()) { + ProxyObject internal = ProxyObject.fromMap(Map.of("value", "internalValue")); + ProxyExecutable proxyExecutable = args -> Value.asValue("test"); + Map val = Map.of("func", proxyExecutable, "object", internal); + ProxyObject p = ProxyObject.fromMap(val); + + ctx.getBindings("js").putMember("p", p); + + assertSame("internalValue", ctx.eval("js", "p?.object?.value").asString()); + assertTrue(ctx.eval("js", "p?.nonexistent?.value").isNull()); + assertSame("test", ctx.eval("js", "p?.func?.()").asString()); + assertTrue(ctx.eval("js", "p?.nonexistent?.()").isNull()); + } + } + +} From 27be42af43da5e5690da0d62197e49c258b32f86 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 14 Jun 2024 21:11:29 +0000 Subject: [PATCH 055/265] Update graal import. --- graal-js/mx.graal-js/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/mx.graal-js/suite.py b/graal-js/mx.graal-js/suite.py index a28832724c0..44170b61183 100644 --- a/graal-js/mx.graal-js/suite.py +++ b/graal-js/mx.graal-js/suite.py @@ -24,7 +24,7 @@ { "name" : "regex", "subdir" : True, - "version" : "af0d8606f490f24c1aebe23e3b6aea693dfd6576", + "version" : "b66e3f298ec0dacedc60b8b794f5319604d06710", "urls" : [ {"url" : "https://github.com/oracle/graal.git", "kind" : "git"}, ] From 9ded5748005680d724744f6fc9ae3cf29a7e79c4 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 14 Jun 2024 21:11:30 +0000 Subject: [PATCH 056/265] Sync CI files. --- common.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/common.json b/common.json index 482ad596be2..02233e65a5d 100644 --- a/common.json +++ b/common.json @@ -4,11 +4,11 @@ "Jsonnet files should not include this file directly but use ci/common.jsonnet instead." ], - "mx_version": "7.25.5", + "mx_version": "7.25.14", "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { - "galahad-jdk": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+1-1", "platformspecific": true, "extrabundles": ["static-libs"]}, + "galahad-jdk": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+2-53", "platformspecific": true, "extrabundles": ["static-libs"]}, "oraclejdk11": {"name": "jpg-jdk", "version": "11.0.11", "build_id": "jdk-11.0.11+9", "platformspecific": true, "extrabundles": ["static-libs"] }, @@ -45,13 +45,13 @@ "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.2+13-jvmci-23.1-b33-sulong", "platformspecific": true }, "graalvm-ee-21": {"name": "graalvm-java21", "version": "23.1.3", "platformspecific": true }, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+1", "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+1-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+1-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+1-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+1-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+1-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+1-jvmci-b01-sulong", "platformspecific": true } + "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+2", "platformspecific": true, "extrabundles": ["static-libs"]}, + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+2-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+2-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+2-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+2-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+2-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+2-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { From 1a447415f27c8ccf47f825047481ac0b6699c6e7 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Sun, 16 Jun 2024 02:23:56 +0200 Subject: [PATCH 057/265] Maven demo: Update compiler module names (renamed in 24.0). --- graal-js/test/maven-demo/pom.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/graal-js/test/maven-demo/pom.xml b/graal-js/test/maven-demo/pom.xml index c403ed0fd9f..502654c32fa 100644 --- a/graal-js/test/maven-demo/pom.xml +++ b/graal-js/test/maven-demo/pom.xml @@ -225,10 +225,11 @@ 3.1.0 + com.mycompany.app - jdk.internal.vm.compiler - jdk.internal.vm.compiler.management + jdk.graal.compiler + jdk.graal.compiler.management org.graalvm.truffle org.graalvm.truffle.compiler org.graalvm.truffle.runtime From ba41849fea11646d1b1d3d68c3ff6139084faf4e Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Sun, 16 Jun 2024 02:25:13 +0200 Subject: [PATCH 058/265] Maven demo: Add newly required --add-exports java.base/jdk.internal.misc=jdk.graal.compiler. --- graal-js/test/maven-demo/pom.xml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/graal-js/test/maven-demo/pom.xml b/graal-js/test/maven-demo/pom.xml index 502654c32fa..d8b67009f43 100644 --- a/graal-js/test/maven-demo/pom.xml +++ b/graal-js/test/maven-demo/pom.xml @@ -48,7 +48,7 @@ my-app http://maven.apache.org - 23.1.0 + 24.1.0 ${project.build.directory}/compiler @@ -120,7 +120,7 @@ maven-surefire-plugin 3.1.2 - -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI --upgrade-module-path=${compiler.dir} + -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI --add-exports=java.base/jdk.internal.misc=jdk.graal.compiler --upgrade-module-path=${compiler.dir} @@ -194,6 +194,7 @@ -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI + --add-exports=java.base/jdk.internal.misc=jdk.graal.compiler --upgrade-module-path=${compiler.dir} -m com.mycompany.app/com.mycompany.app.App @@ -242,7 +243,7 @@ myapp=com.mycompany.app/com.mycompany.app.App - "-XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI" + "-XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI --add-exports=java.base/jdk.internal.misc=jdk.graal.compiler" From 5b6da3e13cc68092c10c8547813c0275c9234628 Mon Sep 17 00:00:00 2001 From: Danilo Ansaloni Date: Wed, 19 Jun 2024 20:39:42 +0200 Subject: [PATCH 059/265] Developer info is consistent with other suites. --- graal-js/mx.graal-js/suite.py | 6 +++--- graal-nodejs/mx.graal-nodejs/suite.py | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/graal-js/mx.graal-js/suite.py b/graal-js/mx.graal-js/suite.py index 44170b61183..793503724c3 100644 --- a/graal-js/mx.graal-js/suite.py +++ b/graal-js/mx.graal-js/suite.py @@ -8,9 +8,9 @@ "groupId" : "org.graalvm.js", "url" : "http://www.graalvm.org/", "developer" : { - "name" : "Truffle and Graal developers", - "email" : "graalvm-users@oss.oracle.com", - "organization" : "Graal", + "name" : "GraalVM Development", + "email" : "graalvm-dev@oss.oracle.com", + "organization" : "Oracle Corporation", "organizationUrl" : "http://www.graalvm.org/", }, "scm" : { diff --git a/graal-nodejs/mx.graal-nodejs/suite.py b/graal-nodejs/mx.graal-nodejs/suite.py index ac505700011..7d4b4aad19a 100644 --- a/graal-nodejs/mx.graal-nodejs/suite.py +++ b/graal-nodejs/mx.graal-nodejs/suite.py @@ -14,10 +14,10 @@ }, "developer" : { - "name" : "Graal JS developers", - "email" : "graal_js_ww_grp@oracle.com", - "organization" : "Graal JS", - "organizationUrl" : "https://labs.oracle.com/pls/apex/f?p=labs:49:::::P49_PROJECT_ID:129", + "name" : "GraalVM Development", + "email" : "graalvm-dev@oss.oracle.com", + "organization" : "Oracle Corporation", + "organizationUrl" : "http://www.graalvm.org/", }, "url" : "http://www.oracle.com/technetwork/oracle-labs/program-languages/overview/index.html", From be79811939cd5d91819ebbca6283d839d82832f9 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Thu, 20 Jun 2024 19:24:09 +0200 Subject: [PATCH 060/265] %TypedArray%.prototype.map should use Set (not CreateDataPropertyOrThrow). --- .../com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java index 35c74230e5e..49b0e2b07fd 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java @@ -2422,7 +2422,7 @@ protected Object map(Object thisObj, Object callback, Object thisArg) { @Override protected MaybeResultNode makeMaybeResultNode() { return new ForEachIndexCallNode.MaybeResultNode() { - @Child private WriteElementNode writeOwnNode = WriteElementNode.create(getContext(), true, true); + @Child private WriteElementNode writeOwnNode = WriteElementNode.create(getContext(), true, !isTypedArrayImplementation); @Override public MaybeResult apply(long index, Object value, Object callbackResult, Object currentResult) { From bfaaa4e8bb4cd54b9c521e22c89b82286820b51f Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Thu, 20 Jun 2024 19:25:13 +0200 Subject: [PATCH 061/265] Regression test of the usage of Set in %TypedArray%.prototype.map. --- .../com.oracle.truffle.js.test/js/GR-54881.js | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 graal-js/src/com.oracle.truffle.js.test/js/GR-54881.js diff --git a/graal-js/src/com.oracle.truffle.js.test/js/GR-54881.js b/graal-js/src/com.oracle.truffle.js.test/js/GR-54881.js new file mode 100644 index 00000000000..e1bc1593ade --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/js/GR-54881.js @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ + +// Checks that %TypedArray%.prototype.map uses Set (not CreateDataPropertyOrThrow) + +load("assert.js"); + +var buffer = new ArrayBuffer(8); +var array = new Uint8Array(buffer); +var ctor = function() { return array; }; +ctor[Symbol.species] = ctor; +array.constructor = ctor; + +var calls = 0; +array.map(function(_,i) { + calls++; + if (i === 1) buffer.transfer(); +}); + +assertSame(8, calls); From 65516ad95f296cf1f53391f933c1888f71746837 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Thu, 20 Jun 2024 19:27:36 +0200 Subject: [PATCH 062/265] Updating the status of TestV8 test-suite. --- graal-js/test/testV8.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/graal-js/test/testV8.json b/graal-js/test/testV8.json index d31f74d910c..8e8859e2a9a 100644 --- a/graal-js/test/testV8.json +++ b/graal-js/test/testV8.json @@ -597,6 +597,10 @@ "filePath" : "mjsunit/es6/typedarray-construct-offset-not-smi.js", "status" : "FAIL", "comment" : "TODO: evaluate (V8 tests update 2017-07-07)" + }, { + "filePath" : "mjsunit/es6/typedarray-map.js", + "status" : "FAIL", + "comment" : "Off-spec test." }, { "filePath" : "mjsunit/es6/typedarray-of.js", "runInIsolation" : true, From 314aa991d178fd3874c1238972902d52ef224616 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 21 Jun 2024 21:07:00 +0000 Subject: [PATCH 063/265] Update graal import. --- graal-js/mx.graal-js/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/mx.graal-js/suite.py b/graal-js/mx.graal-js/suite.py index 793503724c3..cf9b2d12ecc 100644 --- a/graal-js/mx.graal-js/suite.py +++ b/graal-js/mx.graal-js/suite.py @@ -24,7 +24,7 @@ { "name" : "regex", "subdir" : True, - "version" : "b66e3f298ec0dacedc60b8b794f5319604d06710", + "version" : "4186b49c88690386fce71af0c7ad8a5a341d6d8e", "urls" : [ {"url" : "https://github.com/oracle/graal.git", "kind" : "git"}, ] From 05e0bb1f36e6eca56c66cef6c30ed007ae9f853f Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 21 Jun 2024 21:07:00 +0000 Subject: [PATCH 064/265] Sync CI files. --- common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common.json b/common.json index 02233e65a5d..f2ac2a82090 100644 --- a/common.json +++ b/common.json @@ -4,7 +4,7 @@ "Jsonnet files should not include this file directly but use ci/common.jsonnet instead." ], - "mx_version": "7.25.14", + "mx_version": "7.26.0", "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { From 07e03cd4cd70d81e4d571431ac9d1d0f12e28ae4 Mon Sep 17 00:00:00 2001 From: Roland Schatz Date: Thu, 20 Jun 2024 14:21:18 +0200 Subject: [PATCH 065/265] Enforce strong digest checks on all build dependency downloads. --- graal-js/mx.graal-js/suite.py | 2 +- graal-nodejs/mx.graal-nodejs/suite.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/graal-js/mx.graal-js/suite.py b/graal-js/mx.graal-js/suite.py index cf9b2d12ecc..13fa79f94a6 100644 --- a/graal-js/mx.graal-js/suite.py +++ b/graal-js/mx.graal-js/suite.py @@ -1,5 +1,5 @@ suite = { - "mxversion" : "6.41.0", + "mxversion" : "7.27.0", "name" : "graal-js", diff --git a/graal-nodejs/mx.graal-nodejs/suite.py b/graal-nodejs/mx.graal-nodejs/suite.py index 7d4b4aad19a..52171d69cc1 100644 --- a/graal-nodejs/mx.graal-nodejs/suite.py +++ b/graal-nodejs/mx.graal-nodejs/suite.py @@ -1,6 +1,6 @@ suite = { - "mxversion" : "6.27.1", + "mxversion" : "7.27.0", "name" : "graal-nodejs", "versionConflictResolution" : "latest", @@ -45,7 +45,7 @@ "windows" : { "amd64" : { "urls": ["https://lafo.ssw.uni-linz.ac.at/pub/graal-external-deps/truffle/nodejs/nasm-2.14.02-windows-amd64.tar.gz"], - "sha1": "2a7caf509b5d9f56fad303538d2a5f0e783e7a1e", + "digest": "sha512:f11495fe7b3b50587161d5cc9e604770c0470aef04468865e7d775d96dbdc33903989ee76aed51ec09f923da452be50993bc7b3aa73b635fc93c7bca17807951", }, "": { "optional": True, From aca6e38086b8241fcefab5ada945cde426013fea Mon Sep 17 00:00:00 2001 From: Roland Schatz Date: Tue, 25 Jun 2024 10:34:01 +0200 Subject: [PATCH 066/265] Update graal import. --- common.json | 2 +- graal-js/mx.graal-js/suite.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common.json b/common.json index f2ac2a82090..e187a210197 100644 --- a/common.json +++ b/common.json @@ -4,7 +4,7 @@ "Jsonnet files should not include this file directly but use ci/common.jsonnet instead." ], - "mx_version": "7.26.0", + "mx_version": "7.27.0", "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { diff --git a/graal-js/mx.graal-js/suite.py b/graal-js/mx.graal-js/suite.py index 13fa79f94a6..7941b4cffdf 100644 --- a/graal-js/mx.graal-js/suite.py +++ b/graal-js/mx.graal-js/suite.py @@ -24,7 +24,7 @@ { "name" : "regex", "subdir" : True, - "version" : "4186b49c88690386fce71af0c7ad8a5a341d6d8e", + "version" : "01f3be02bb8e99e910959c1f266a69f651b5dc08", "urls" : [ {"url" : "https://github.com/oracle/graal.git", "kind" : "git"}, ] From 4b56fea4e8256f2a643376f768e4b933a18fb0ab Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 25 Jun 2024 12:36:26 +0200 Subject: [PATCH 067/265] Install black formatter in CI style gates and exclude files in graal-nodejs. --- common.jsonnet | 2 +- graal-nodejs/pyproject.toml | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/common.jsonnet b/common.jsonnet index 77d7bd06ede..fded1a0b46f 100644 --- a/common.jsonnet +++ b/common.jsonnet @@ -112,7 +112,7 @@ targets + timelimit: if 'timelimit' in super then super.timelimit else '45:00', }, - gateStyleFullBuild:: common.deps.pylint + common.deps.eclipse + common.deps.jdt + { + gateStyleFullBuild:: common.deps.pylint + common.deps.black + common.deps.eclipse + common.deps.jdt + { local is_jdk_latest = 'jdk_name' in self && self.jdk_name == 'jdk-latest', local strict = !is_jdk_latest, // Add JDK21 to EXTRA_JAVA_HOMES for SpotBugs. diff --git a/graal-nodejs/pyproject.toml b/graal-nodejs/pyproject.toml index d8b53dc20ee..1d5fc11aaaa 100644 --- a/graal-nodejs/pyproject.toml +++ b/graal-nodejs/pyproject.toml @@ -51,3 +51,7 @@ max-args = 12 max-branches = 110 max-returns = 12 max-statements = 289 + +# Exclude all files from `mx pyformat` +[tool.black] +force-exclude = '.*' From 729a34fbc6a79065b1f5b2d16da0ee64d6b52f37 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Tue, 25 Jun 2024 14:26:55 +0200 Subject: [PATCH 068/265] Do not provide Error.stackTraceLimit by default. --- .../access/ErrorStackTraceLimitNode.java | 22 ++++++++++++------- .../truffle/js/runtime/JSException.java | 21 +++++++++++------- .../oracle/truffle/js/runtime/JSRealm.java | 8 +++++++ .../truffle/js/runtime/builtins/JSError.java | 2 -- 4 files changed, 35 insertions(+), 18 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ErrorStackTraceLimitNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ErrorStackTraceLimitNode.java index a0221de0a43..31212b67944 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ErrorStackTraceLimitNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ErrorStackTraceLimitNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -46,6 +46,7 @@ import com.oracle.truffle.js.nodes.JavaScriptBaseNode; import com.oracle.truffle.js.nodes.cast.IsNumberNode; import com.oracle.truffle.js.nodes.cast.JSToIntegerAsLongNode; +import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSErrorType; import com.oracle.truffle.js.runtime.builtins.JSError; import com.oracle.truffle.js.runtime.builtins.JSFunctionObject; @@ -68,15 +69,20 @@ public static ErrorStackTraceLimitNode create() { protected final int doInt( @Cached IsNumberNode isNumber, @Cached JSToIntegerAsLongNode toInteger) { - JSFunctionObject errorConstructor = getRealm().getErrorConstructor(JSErrorType.Error); - if (JSProperty.isData(getStackTraceLimit.getPropertyFlagsOrDefault(errorConstructor, JSError.STACK_TRACE_LIMIT_PROPERTY_NAME, JSProperty.ACCESSOR))) { - Object value = getStackTraceLimit.getOrDefault(errorConstructor, JSError.STACK_TRACE_LIMIT_PROPERTY_NAME, Undefined.instance); - if (isNumber.execute(this, value)) { - long limit = toInteger.executeLong(value); - return (int) Math.max(0, Math.min(limit, Integer.MAX_VALUE)); + JSContext context = getJSContext(); + if (context.isOptionV8CompatibilityMode()) { + JSFunctionObject errorConstructor = getRealm().getErrorConstructor(JSErrorType.Error); + if (JSProperty.isData(getStackTraceLimit.getPropertyFlagsOrDefault(errorConstructor, JSError.STACK_TRACE_LIMIT_PROPERTY_NAME, JSProperty.ACCESSOR))) { + Object value = getStackTraceLimit.getOrDefault(errorConstructor, JSError.STACK_TRACE_LIMIT_PROPERTY_NAME, Undefined.instance); + if (isNumber.execute(this, value)) { + long limit = toInteger.executeLong(value); + return (int) Math.max(0, Math.min(limit, Integer.MAX_VALUE)); + } } + return 0; + } else { + return context.getLanguageOptions().stackTraceLimit(); } - return 0; } public abstract int executeInt(); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSException.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSException.java index d80c8ae0b50..a07d27cb376 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSException.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSException.java @@ -150,16 +150,21 @@ public static JSException create(JSErrorType type, String message, Throwable cau } public static int getStackTraceLimit(JSRealm realm) { - JSFunctionObject errorConstructor = realm.getErrorConstructor(JSErrorType.Error); - DynamicObjectLibrary lib = DynamicObjectLibrary.getUncached(); - if (JSProperty.isData(lib.getPropertyFlagsOrDefault(errorConstructor, JSError.STACK_TRACE_LIMIT_PROPERTY_NAME, JSProperty.ACCESSOR))) { - Object stackTraceLimit = lib.getOrDefault(errorConstructor, JSError.STACK_TRACE_LIMIT_PROPERTY_NAME, Undefined.instance); - if (JSRuntime.isNumber(stackTraceLimit)) { - final long limit = JSRuntime.toInteger((Number) stackTraceLimit); - return (int) Math.max(0, Math.min(limit, Integer.MAX_VALUE)); + JSContextOptions contextOptions = realm.getContextOptions(); + if (contextOptions.isV8CompatibilityMode()) { + JSFunctionObject errorConstructor = realm.getErrorConstructor(JSErrorType.Error); + DynamicObjectLibrary lib = DynamicObjectLibrary.getUncached(); + if (JSProperty.isData(lib.getPropertyFlagsOrDefault(errorConstructor, JSError.STACK_TRACE_LIMIT_PROPERTY_NAME, JSProperty.ACCESSOR))) { + Object stackTraceLimit = lib.getOrDefault(errorConstructor, JSError.STACK_TRACE_LIMIT_PROPERTY_NAME, Undefined.instance); + if (JSRuntime.isNumber(stackTraceLimit)) { + final long limit = JSRuntime.toInteger((Number) stackTraceLimit); + return (int) Math.max(0, Math.min(limit, Integer.MAX_VALUE)); + } } + return 0; + } else { + return contextOptions.getStackTraceLimit(); } - return 0; } @Override diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java index d16ab76b719..df9c651fd1c 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java @@ -2246,6 +2246,7 @@ public void addOptionalGlobals() { setupJavaInterop(); } addCommonJSGlobals(); + addErrorStackTraceLimit(); } private void addGlobalGlobal() { @@ -2254,6 +2255,13 @@ private void addGlobalGlobal() { } } + private void addErrorStackTraceLimit() { + if (getContextOptions().isV8CompatibilityMode()) { + JSObject errorConstructor = getErrorConstructor(JSErrorType.Error); + JSObjectUtil.putDataProperty(errorConstructor, JSError.STACK_TRACE_LIMIT_PROPERTY_NAME, getContextOptions().getStackTraceLimit(), JSAttributes.getDefault()); + } + } + private void addShellGlobals() { if (getContextOptions().isShell()) { GlobalBuiltins.GLOBAL_SHELL.forEachBuiltin((Builtin builtin) -> { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSError.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSError.java index fdd51cd285d..9f38f67c0f4 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSError.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSError.java @@ -54,7 +54,6 @@ import com.oracle.truffle.js.runtime.GraalJSException; import com.oracle.truffle.js.runtime.GraalJSException.JSStackTraceElement; import com.oracle.truffle.js.runtime.JSContext; -import com.oracle.truffle.js.runtime.JSContextOptions; import com.oracle.truffle.js.runtime.JSErrorType; import com.oracle.truffle.js.runtime.JSException; import com.oracle.truffle.js.runtime.JSRealm; @@ -212,7 +211,6 @@ public static JSConstructor createErrorConstructor(JSRealm realm, JSErrorType er JSObjectUtil.putConstructorPrototypeProperty(errorConstructor, classPrototype); if (errorType == JSErrorType.Error) { JSObjectUtil.putFunctionsFromContainer(realm, errorConstructor, ErrorFunctionBuiltins.BUILTINS); - JSObjectUtil.putDataProperty(errorConstructor, STACK_TRACE_LIMIT_PROPERTY_NAME, JSContextOptions.STACK_TRACE_LIMIT.getValue(realm.getOptions()), JSAttributes.getDefault()); } return new JSConstructor(errorConstructor, classPrototype); From d1d20609c157583e8cba282a3d8f3afa450ab339 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Tue, 25 Jun 2024 14:27:45 +0200 Subject: [PATCH 069/265] Ignore Error.prepareStackTrace outside v8-compat mode. --- .../oracle/truffle/js/runtime/builtins/JSError.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSError.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSError.java index 9f38f67c0f4..9deb1a8676d 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSError.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSError.java @@ -313,10 +313,12 @@ public static Object prepareStack(JSRealm realm, JSDynamicObject errorObj, Graal */ @TruffleBoundary public static Object prepareStackNoCallback(JSRealm realm, JSDynamicObject errorObj, JSStackTraceElement[] jsStackTrace) { - JSFunctionObject error = realm.getErrorConstructor(JSErrorType.Error); - Object prepareStackTrace = JSObject.get(error, PREPARE_STACK_TRACE_NAME); - if (JSFunction.isJSFunction(prepareStackTrace)) { - return prepareStackWithUserFunction(realm, (JSFunctionObject) prepareStackTrace, errorObj, jsStackTrace); + if (realm.getContextOptions().isV8CompatibilityMode()) { + JSFunctionObject error = realm.getErrorConstructor(JSErrorType.Error); + Object prepareStackTrace = JSObject.get(error, PREPARE_STACK_TRACE_NAME); + if (JSFunction.isJSFunction(prepareStackTrace)) { + return prepareStackWithUserFunction(realm, (JSFunctionObject) prepareStackTrace, errorObj, jsStackTrace); + } } return formatStackTrace(jsStackTrace, errorObj, realm); } From c13a6c4695eceb09922f40c9de3a9acf3ec6ed6d Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Tue, 25 Jun 2024 14:50:42 +0200 Subject: [PATCH 070/265] Test that error-stack-related extensions are not enabled by default. --- .../com.oracle.truffle.js.test/js/GR-54930.js | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 graal-js/src/com.oracle.truffle.js.test/js/GR-54930.js diff --git a/graal-js/src/com.oracle.truffle.js.test/js/GR-54930.js b/graal-js/src/com.oracle.truffle.js.test/js/GR-54930.js new file mode 100644 index 00000000000..10e61d0d3a7 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/js/GR-54930.js @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ + +load("assert.js"); + +function createError(n) { + return n ? createError(n-1) : new Error(); +} + +// Error.stackTraceLimit should have no impact on the stack property +var expected = createError(10).stack; + +for (var i = 0; i < 5; i++) { + Error.stackTraceLimit = i; + assertSame(expected, createError(10).stack); +} + +// Error.prepareStackTrace should not be invoked +var invoked = false; +Error.prepareStackTrace = function() { + invoked = true; +}; + +new Error().stack; +assertFalse(invoked); + +// Error.prepareStackTrace should not be read +var read = false; +Object.defineProperty(Error, 'prepareStackTrace', { + get() { + read = true; + } +}); + +new Error().stack; +assertFalse(read); From 294592edd64cd9fb2701f176a47782bca019170f Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Tue, 25 Jun 2024 14:51:58 +0200 Subject: [PATCH 071/265] Tests using Error.prepareStackTrace/stackTraceLimit should use v8-compat mode. --- graal-js/src/com.oracle.truffle.js.test/js/GR-53714.js | 1 + graal-js/src/com.oracle.truffle.js.test/js/callsite.js | 2 ++ .../js/runtime/error_stacktracelimit.js | 2 ++ 3 files changed, 5 insertions(+) diff --git a/graal-js/src/com.oracle.truffle.js.test/js/GR-53714.js b/graal-js/src/com.oracle.truffle.js.test/js/GR-53714.js index ff2901f56eb..0d74c8b91dd 100644 --- a/graal-js/src/com.oracle.truffle.js.test/js/GR-53714.js +++ b/graal-js/src/com.oracle.truffle.js.test/js/GR-53714.js @@ -9,6 +9,7 @@ * Regression test of the handling of long values. * * @option temporal + * @option v8-compat */ load('assert.js'); diff --git a/graal-js/src/com.oracle.truffle.js.test/js/callsite.js b/graal-js/src/com.oracle.truffle.js.test/js/callsite.js index fec124eaa2b..c75c9e93ccf 100644 --- a/graal-js/src/com.oracle.truffle.js.test/js/callsite.js +++ b/graal-js/src/com.oracle.truffle.js.test/js/callsite.js @@ -7,6 +7,8 @@ /** * Tests of CallSite built-ins. + * + * @option v8-compat */ load('assert.js'); diff --git a/graal-js/src/com.oracle.truffle.js.test/js/runtime/error_stacktracelimit.js b/graal-js/src/com.oracle.truffle.js.test/js/runtime/error_stacktracelimit.js index 962ec0b45ed..620f4b1313f 100644 --- a/graal-js/src/com.oracle.truffle.js.test/js/runtime/error_stacktracelimit.js +++ b/graal-js/src/com.oracle.truffle.js.test/js/runtime/error_stacktracelimit.js @@ -6,6 +6,8 @@ */ /* * Test that getting Error.stackTraceLimit is side-effect-free. + * + * @option v8-compat */ class MyError extends Error { From db7545b54ce633e81b06c0a5b30cdbe24b544cc5 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Thu, 27 Jun 2024 15:03:31 +0200 Subject: [PATCH 072/265] Do not override the deprecated isCaptureFramesForTrace(Node). --- .../truffle/js/nodes/promise/PromiseReactionJobNode.java | 3 +-- .../src/com/oracle/truffle/js/runtime/JavaScriptRootNode.java | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/PromiseReactionJobNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/PromiseReactionJobNode.java index c1dfbf96dcc..d8d9173a01c 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/PromiseReactionJobNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/PromiseReactionJobNode.java @@ -51,7 +51,6 @@ import com.oracle.truffle.api.instrumentation.ProbeNode; import com.oracle.truffle.api.instrumentation.StandardTags; import com.oracle.truffle.api.instrumentation.Tag; -import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.HiddenKey; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.js.nodes.JavaScriptBaseNode; @@ -213,7 +212,7 @@ private TryCatchNode.GetErrorObjectNode getErrorObject() { } @Override - public boolean isCaptureFramesForTrace(@SuppressWarnings("unused") Node currentNode) { + public boolean isCaptureFramesForTrace(@SuppressWarnings("unused") boolean compiledFrame) { return context.isOptionAsyncStackTraces(); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JavaScriptRootNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JavaScriptRootNode.java index b0757a0f7e7..8a28e1ba5d1 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JavaScriptRootNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JavaScriptRootNode.java @@ -45,7 +45,6 @@ import com.oracle.truffle.api.TruffleStackTraceElement; import com.oracle.truffle.api.frame.Frame; import com.oracle.truffle.api.frame.FrameDescriptor; -import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.api.nodes.RootNode; import com.oracle.truffle.api.source.SourceSection; @@ -109,7 +108,7 @@ public boolean isResumption() { } @Override - public boolean isCaptureFramesForTrace(@SuppressWarnings("unused") Node currentNode) { + public boolean isCaptureFramesForTrace(@SuppressWarnings("unused") boolean compiledFrame) { return isFunction() || isResumption(); } From f8982fc1ca56d02e3d2d825877c34d1453df3d77 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Thu, 27 Jun 2024 23:40:16 +0200 Subject: [PATCH 073/265] Including array elements among members. --- .../truffle/js/runtime/JSContextOptions.java | 10 +++++++++ .../truffle/js/runtime/JSLanguageOptions.java | 3 +++ .../runtime/builtins/JSArgumentsObject.java | 11 +++++++--- .../js/runtime/builtins/JSArrayObject.java | 22 ++++++++++++++----- .../runtime/builtins/JSTypedArrayObject.java | 11 +++++++--- 5 files changed, 45 insertions(+), 12 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java index dd025090837..eff031cf1b7 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java @@ -589,6 +589,11 @@ public Map apply(String value) { public static final OptionKey V8_INTRINSICS = new OptionKey<>(false); @CompilationFinal private boolean v8Intrinsics; + public static final String ARRAY_ELEMENTS_AMONG_MEMBERS_NAME = JS_OPTION_PREFIX + "array-elements-among-members"; + @Option(name = ARRAY_ELEMENTS_AMONG_MEMBERS_NAME, category = OptionCategory.EXPERT, help = "Include array indices in Value.getMemberKeys().") // + public static final OptionKey ARRAY_ELEMENTS_AMONG_MEMBERS = new OptionKey<>(true); + @CompilationFinal private boolean arrayElementsAmongMembers; + public enum UnhandledRejectionsTrackingMode { NONE, WARN, @@ -792,6 +797,7 @@ private void cacheOptions(SandboxPolicy sandboxPolicy) { this.scopeOptimization = readBooleanOption(SCOPE_OPTIMIZATION); this.allowNarrowSpacesInDateFormat = ALLOW_NARROW_SPACES_IN_DATE_FORMAT.hasBeenSet(optionValues) ? readBooleanOption(ALLOW_NARROW_SPACES_IN_DATE_FORMAT) : !isV8CompatibilityMode(); this.v8Intrinsics = readBooleanOption(V8_INTRINSICS); + this.arrayElementsAmongMembers = readBooleanOption(ARRAY_ELEMENTS_AMONG_MEMBERS); } private UnhandledRejectionsTrackingMode readUnhandledRejectionsMode() { @@ -1257,6 +1263,10 @@ public boolean isV8Intrinsics() { return v8Intrinsics; } + public boolean isArrayElementsAmongMembers() { + return arrayElementsAmongMembers; + } + public short getFrequencyBasedPropertyCacheLimit() { return frequencyBasedPropertyCacheLimit; } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSLanguageOptions.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSLanguageOptions.java index 11adc688c68..6f69a5e5d17 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSLanguageOptions.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSLanguageOptions.java @@ -127,6 +127,7 @@ public record JSLanguageOptions( boolean functionStatementError, boolean constAsVar, boolean profileTime, + boolean arrayElementsAmongMembers, String locale) { public static JSLanguageOptions fromOptionValues(SandboxPolicy sandboxPolicy, OptionValues optionValues) { @@ -207,6 +208,7 @@ public static JSLanguageOptions fromContextOptions(JSContextOptions options) { boolean functionStatementError = options.isFunctionStatementError(); boolean constAsVar = options.isConstAsVar(); boolean profileTime = options.isProfileTime(); + boolean arrayElementsAmongMembers = options.isArrayElementsAmongMembers(); String locale = options.getLocale(); return new JSLanguageOptions( @@ -282,6 +284,7 @@ public static JSLanguageOptions fromContextOptions(JSContextOptions options) { functionStatementError, constAsVar, profileTime, + arrayElementsAmongMembers, locale); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArgumentsObject.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArgumentsObject.java index 64afe7244c4..5897dbe11d3 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArgumentsObject.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArgumentsObject.java @@ -118,10 +118,15 @@ public final TruffleString getBuiltinToStringTag() { } @ExportMessage - public final Object getMembers(@SuppressWarnings("unused") boolean includeInternal) { - // Do not include array indices + public final Object getMembers(@SuppressWarnings("unused") boolean includeInternal, + @CachedLibrary("this") InteropLibrary self) { assert JSObject.getJSClass(this) == JSArgumentsArray.INSTANCE; - return InteropArray.create(filterEnumerableNames(this, JSObject.ownPropertyKeys(this), JSArgumentsArray.INSTANCE)); + boolean includeArrayIndices = language(self).getJSContext().getLanguageOptions().arrayElementsAmongMembers(); + if (includeArrayIndices) { + return InteropArray.create(JSObject.enumerableOwnNames(this)); + } else { + return InteropArray.create(filterEnumerableNames(this, JSObject.ownPropertyKeys(this), JSArgumentsArray.INSTANCE)); + } } @SuppressWarnings("static-method") diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayObject.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayObject.java index fee09800666..acde5249d20 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayObject.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayObject.java @@ -114,15 +114,25 @@ public TruffleString getBuiltinToStringTag() { @ExportMessage abstract static class GetMembers { @Specialization(guards = "isJSFastArray(target)") - public static Object fastArray(JSArrayObject target, boolean internal) { - // Do not include array indices - return InteropArray.create(filterEnumerableNames(target, JSNonProxy.ordinaryOwnPropertyKeys(target), JSObject.getJSClass(target))); + public static Object fastArray(JSArrayObject target, boolean internal, + @CachedLibrary("this") InteropLibrary self) { + boolean includeArrayIndices = language(self).getJSContext().getLanguageOptions().arrayElementsAmongMembers(); + if (includeArrayIndices) { + return InteropArray.create(JSObject.enumerableOwnNames(target)); + } else { + return InteropArray.create(filterEnumerableNames(target, JSNonProxy.ordinaryOwnPropertyKeys(target), JSObject.getJSClass(target))); + } } @Specialization(guards = {"!isJSFastArray(target)"}) - public static Object slowArray(JSArrayObject target, boolean internal) { - // Do not include array indices - return InteropArray.create(filterEnumerableNames(target, JSObject.ownPropertyKeys(target), JSObject.getJSClass(target))); + public static Object slowArray(JSArrayObject target, boolean internal, + @CachedLibrary("this") InteropLibrary self) { + boolean includeArrayIndices = language(self).getJSContext().getLanguageOptions().arrayElementsAmongMembers(); + if (includeArrayIndices) { + return InteropArray.create(JSObject.enumerableOwnNames(target)); + } else { + return InteropArray.create(filterEnumerableNames(target, JSObject.ownPropertyKeys(target), JSObject.getJSClass(target))); + } } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java index 6ad2ad160fa..5da80411891 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java @@ -97,10 +97,15 @@ public TruffleString getClassName() { } @ExportMessage - public Object getMembers(@SuppressWarnings("unused") boolean includeInternal) { - // Do not include array indices + public Object getMembers(@SuppressWarnings("unused") boolean includeInternal, + @CachedLibrary("this") InteropLibrary self) { assert JSObject.getJSClass(this) == JSArrayBufferView.INSTANCE; - return InteropArray.create(filterEnumerableNames(this, JSNonProxy.ordinaryOwnPropertyKeys(this), JSArrayBufferView.INSTANCE)); + boolean includeArrayIndices = language(self).getJSContext().getLanguageOptions().arrayElementsAmongMembers(); + if (includeArrayIndices) { + return InteropArray.create(JSObject.enumerableOwnNames(this)); + } else { + return InteropArray.create(filterEnumerableNames(this, JSNonProxy.ordinaryOwnPropertyKeys(this), JSArrayBufferView.INSTANCE)); + } } @SuppressWarnings("static-method") From af52c237045567cbfee817d0b324c69d64c11411 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Mon, 24 Jun 2024 20:07:46 +0200 Subject: [PATCH 074/265] Regression test for the inclusion of array elements among members. --- .../truffle/js/test/regress/GR54917.java | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR54917.java diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR54917.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR54917.java new file mode 100644 index 00000000000..813f15a0284 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR54917.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.test.regress; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.Value; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import com.oracle.truffle.js.runtime.JSContextOptions; +import com.oracle.truffle.js.test.JSTest; + +@RunWith(Parameterized.class) +public class GR54917 { + + @Parameterized.Parameters(name = "{0}") + public static List data() { + return Arrays.asList(Boolean.TRUE, Boolean.FALSE); + } + + @Parameterized.Parameter(value = 0) public boolean arrayElementsAmongMembers; + + @Test + public void testArray() { + testIt("[]"); + } + + @Test + public void testTypedArray() { + testIt("new Uint8Array(2)"); + } + + @Test + public void testArguments() { + testIt("(function() { return arguments; })()"); + } + + private void testIt(String arrayInit) { + try (Context ctx = JSTest.newContextBuilder().option(JSContextOptions.ARRAY_ELEMENTS_AMONG_MEMBERS_NAME, String.valueOf(arrayElementsAmongMembers)).allowAllAccess(true).build()) { + Value array = ctx.eval("js", "var array = " + arrayInit + "; array[0] = 2; array[1] = 4; array.myFlag = true; array"); + + Set expected = arrayElementsAmongMembers ? Set.of("0", "1", "myFlag") : Set.of("myFlag"); + assertEquals(expected, array.getMemberKeys()); + + checkMap(array.as(Map.class)); + + ctx.getBindings("js").putMember("o", this); + ctx.eval("js", "o.callback(array);"); + } + } + + public void callback(Map map) { + checkMap(map); + } + + private void checkMap(Map map) { + assertEquals(arrayElementsAmongMembers ? 3 : 1, map.size()); + assertEquals(true, map.get("myFlag")); + if (arrayElementsAmongMembers) { + assertEquals(2, ((Number) map.get("0")).intValue()); + assertEquals(4, ((Number) map.get("1")).intValue()); + } + } + +} From 29db395a6f92a05f9caed88d409276a557b6f433 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Mon, 24 Jun 2024 20:11:03 +0200 Subject: [PATCH 075/265] Updating unit tests to expect array elements among members. --- .../ScriptEngineArrayTypeMappingTest.java | 4 +- .../js/test/interop/InteropArrayTest.java | 76 +++---------------- .../js/test/polyglot/PolyglotBuiltinTest.java | 4 +- 3 files changed, 15 insertions(+), 69 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js.scriptengine.test/src/com/oracle/truffle/js/scriptengine/test/ScriptEngineArrayTypeMappingTest.java b/graal-js/src/com.oracle.truffle.js.scriptengine.test/src/com/oracle/truffle/js/scriptengine/test/ScriptEngineArrayTypeMappingTest.java index 99369129275..d262d25f3d3 100644 --- a/graal-js/src/com.oracle.truffle.js.scriptengine.test/src/com/oracle/truffle/js/scriptengine/test/ScriptEngineArrayTypeMappingTest.java +++ b/graal-js/src/com.oracle.truffle.js.scriptengine.test/src/com/oracle/truffle/js/scriptengine/test/ScriptEngineArrayTypeMappingTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -104,7 +104,7 @@ public void testJavaScriptArrayViaScriptEngineAsMap() throws ScriptException { Assert.assertFalse(result instanceof List); Assert.assertTrue(result instanceof Map); - Assert.assertEquals(0, ((Map) result).size()); + Assert.assertEquals(3, ((Map) result).size()); } } diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/InteropArrayTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/InteropArrayTest.java index 152c300b660..d665a2bd03a 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/InteropArrayTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/InteropArrayTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -47,11 +47,11 @@ import java.io.ByteArrayOutputStream; import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -71,8 +71,8 @@ */ public class InteropArrayTest { /** - * Test that fast JS array indices are not in member keys (which contains only enumerable - * properties) and that both getMember and getArrayElement works on them. + * Test that fast JS array indices are in member keys and that both getMember and + * getArrayElement work on them. */ @Test public void testArrayGetMembers() { @@ -83,66 +83,12 @@ public void testArrayGetMembers() { assertEquals(3, array.getArrayElement(0).asInt()); assertEquals(1, array.getMember("2").asInt()); assertEquals(1, array.getArrayElement(2).asInt()); - assertTrue(array.getMemberKeys().toString(), array.getMemberKeys().isEmpty()); + assertEquals(array.getMemberKeys().toString(), Set.of("0", "1", "2", "3"), array.getMemberKeys()); } } /** - * Test that slow JS array indices are not in member keys and also overridden index is not in - * member keys. - */ - @Test - public void testSlowArrayGetMembers() { - try (Context context = JSTest.newContextBuilder().build()) { - Value array = context.eval(ID, "var a = [3, 4, 1, 5]; Object.defineProperty(a, 2, {get: function(){return" + - " 42;}}); a;"); - assertEquals(4, array.getArraySize()); - assertEquals(3, array.getMember("0").asInt()); - assertEquals(3, array.getArrayElement(0).asInt()); - assertEquals(42, array.getMember("2").asInt()); - assertEquals(42, array.getArrayElement(2).asInt()); - assertTrue(array.getMemberKeys().toString(), array.getMemberKeys().isEmpty()); - } - } - - /** - * Test that JS array's enumerable property with integer key specified as integer is not in - * member keys. - */ - @Test - public void testSlowArrayWithIntKeyEnumerablePropertyGetMembers1() { - try (Context context = JSTest.newContextBuilder().build()) { - Value array = context.eval(ID, "var a = [3, 4, 1, 5]; Object.defineProperty(a, 2, {get: function(){return" + - " 42;}, enumerable: true}); a;"); - assertEquals(4, array.getArraySize()); - assertEquals(3, array.getMember("0").asInt()); - assertEquals(3, array.getArrayElement(0).asInt()); - assertEquals(42, array.getMember("2").asInt()); - assertEquals(42, array.getArrayElement(2).asInt()); - assertTrue(array.getMemberKeys().toString(), array.getMemberKeys().isEmpty()); - } - } - - /** - * Test that JS array's enumerable property with integer key specified as string is not in - * member keys. - */ - @Test - public void testSlowArrayWithIntKeyEnumerablePropertyGetMembers2() { - try (Context context = JSTest.newContextBuilder().build()) { - Value array = context.eval(ID, "var a = [3, 4, 1, 5]; Object.defineProperty(a, '2', {get: function()" + - "{return 42;}, enumerable: true}); a;"); - assertEquals(4, array.getArraySize()); - assertEquals(3, array.getMember("0").asInt()); - assertEquals(3, array.getArrayElement(0).asInt()); - assertEquals(42, array.getMember("2").asInt()); - assertEquals(42, array.getArrayElement(2).asInt()); - assertTrue(array.getMemberKeys().toString(), array.getMemberKeys().isEmpty()); - } - } - - /** - * Test that JS array's enumerable property with string key is the only element of member keys. + * Test that JS array's enumerable property with string key is the element of member keys. */ @Test public void testSlowArrayWithStringKeyEnumerablePropertyGetMembers() { @@ -155,12 +101,12 @@ public void testSlowArrayWithStringKeyEnumerablePropertyGetMembers() { assertEquals(1, array.getMember("2").asInt()); assertEquals(1, array.getArrayElement(2).asInt()); assertEquals(42, array.getMember("x").asInt()); - assertEquals(array.getMemberKeys().toString(), Collections.singleton("x"), array.getMemberKeys()); + assertEquals(array.getMemberKeys().toString(), Set.of("0", "1", "2", "3", "x"), array.getMemberKeys()); } } /** - * Test that typed JS array indices are not in member keys (enumberable properties). + * Test that typed JS array indices are in member keys. */ @Test public void testTypedArrayGetMembers() { @@ -171,12 +117,12 @@ public void testTypedArrayGetMembers() { assertEquals(3, array.getArrayElement(0).asInt()); assertEquals(1, array.getMember("2").asInt()); assertEquals(1, array.getArrayElement(2).asInt()); - assertTrue(array.getMemberKeys().toString(), array.getMemberKeys().isEmpty()); + assertEquals(array.getMemberKeys().toString(), Set.of("0", "1", "2", "3"), array.getMemberKeys()); } } /** - * Test that arguments JS array indices are not in member keys (enumerable properties). + * Test that arguments JS array indices are in member keys. */ @Test public void testArgumentsObjectGetMembers() { @@ -187,7 +133,7 @@ public void testArgumentsObjectGetMembers() { assertEquals(3, array.getArrayElement(0).asInt()); assertEquals(1, array.getMember("2").asInt()); assertEquals(1, array.getArrayElement(2).asInt()); - assertTrue(array.getMemberKeys().toString(), array.getMemberKeys().isEmpty()); + assertEquals(array.getMemberKeys().toString(), Set.of("0", "1", "2", "3"), array.getMemberKeys()); } } diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/polyglot/PolyglotBuiltinTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/polyglot/PolyglotBuiltinTest.java index ee4630787da..5d3bff3fe0b 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/polyglot/PolyglotBuiltinTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/polyglot/PolyglotBuiltinTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -214,7 +214,7 @@ public void testHasKeys() { @Test public void testKeys() { - assertEquals("0", test("''+Polyglot.keys([1,2,3]).length;")); + assertEquals("3", test("''+Polyglot.keys([1,2,3]).length;")); assertEquals("1", test("''+Polyglot.keys({a:1}).length;")); test("''+Polyglot.keys(1);", "non-interop object"); } From cb4f8c38588a5e23bb56680720205e7c25ca6b19 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Mon, 24 Jun 2024 20:14:48 +0200 Subject: [PATCH 076/265] Allow to use INSIGHT_HEAP distribution from 'mx js' and 'mx node'. --- graal-js/mx.graal-js/mx_graal_js.py | 2 +- graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/graal-js/mx.graal-js/mx_graal_js.py b/graal-js/mx.graal-js/mx_graal_js.py index b228ae9e51b..906cbc7db60 100644 --- a/graal-js/mx.graal-js/mx_graal_js.py +++ b/graal-js/mx.graal-js/mx_graal_js.py @@ -274,7 +274,7 @@ def graaljs_cmd_line(args, append_default_args=True, jdk=None): jdk = get_jdk() runtime_jvm_args = mx.get_runtime_jvm_args(['GRAALJS_LAUNCHER', 'GRAALJS'] + mx_truffle.resolve_truffle_dist_names() - + (['tools:CHROMEINSPECTOR', 'tools:TRUFFLE_PROFILER', 'tools:INSIGHT'] if mx.suite('tools', fatalIfMissing=False) is not None else []) + + (['tools:CHROMEINSPECTOR', 'tools:TRUFFLE_PROFILER', 'tools:INSIGHT', 'tools:INSIGHT_HEAP'] if mx.suite('tools', fatalIfMissing=False) is not None else []) + (['wasm:WASM'] if mx.suite('wasm', fatalIfMissing=False) is not None else []), jdk=jdk) main_dist = mx.distribution('GRAALJS_LAUNCHER') diff --git a/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py b/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py index f12fef7b20f..9c84cec5e50 100644 --- a/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py +++ b/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py @@ -461,7 +461,7 @@ def setupNodeEnvironment(args, add_graal_vm_args=True): node_jvm_mp = (os.environ['NODE_JVM_MODULE_PATH'] + pathsep) if 'NODE_JVM_MODULE_PATH' in os.environ else '' node_mp = node_jvm_mp + mx.classpath(['TRUFFLENODE'] + mx_truffle.resolve_truffle_dist_names() - + (['tools:CHROMEINSPECTOR', 'tools:TRUFFLE_PROFILER', 'tools:INSIGHT'] if mx.suite('tools', fatalIfMissing=False) is not None else []) + + (['tools:CHROMEINSPECTOR', 'tools:TRUFFLE_PROFILER', 'tools:INSIGHT', 'tools:INSIGHT_HEAP'] if mx.suite('tools', fatalIfMissing=False) is not None else []) + (['wasm:WASM'] if mx.suite('wasm', fatalIfMissing=False) is not None else [])) _setEnvVar('NODE_JVM_MODULE_PATH', node_mp) _setEnvVar('JAVA_HOME', _java_home()) # when running with the Graal compiler, setting `$JAVA_HOME` to the GraalJDK should be done after calling `mx.classpath()`, which resets `$JAVA_HOME` to the value of the `--java-home` mx cmd line argument From 2f7c44343aeadab55097661f21ad0071ef5153da Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 28 Jun 2024 21:03:46 +0000 Subject: [PATCH 077/265] Update graal import. --- graal-js/mx.graal-js/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/mx.graal-js/suite.py b/graal-js/mx.graal-js/suite.py index 7941b4cffdf..2b8ce309bcc 100644 --- a/graal-js/mx.graal-js/suite.py +++ b/graal-js/mx.graal-js/suite.py @@ -24,7 +24,7 @@ { "name" : "regex", "subdir" : True, - "version" : "01f3be02bb8e99e910959c1f266a69f651b5dc08", + "version" : "940934ae7e0d3b86a9122d5b00bc2789c476a996", "urls" : [ {"url" : "https://github.com/oracle/graal.git", "kind" : "git"}, ] From dc921e2d68d4d76f14a5d9313128ec660c2d66be Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 28 Jun 2024 21:03:47 +0000 Subject: [PATCH 078/265] Sync CI files. --- common.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/common.json b/common.json index e187a210197..efedd632db4 100644 --- a/common.json +++ b/common.json @@ -4,7 +4,7 @@ "Jsonnet files should not include this file directly but use ci/common.jsonnet instead." ], - "mx_version": "7.27.0", + "mx_version": "7.27.1", "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { @@ -45,13 +45,13 @@ "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.2+13-jvmci-23.1-b33-sulong", "platformspecific": true }, "graalvm-ee-21": {"name": "graalvm-java21", "version": "23.1.3", "platformspecific": true }, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+2", "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+2-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+2-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+2-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+2-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+2-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+2-jvmci-b01-sulong", "platformspecific": true } + "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+3", "platformspecific": true, "extrabundles": ["static-libs"]}, + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+3-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+3-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+3-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+3-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+3-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+3-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { From 53fb84a4cfbc3cc7019e74338a1e7944de164561 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 5 Jul 2024 21:03:40 +0000 Subject: [PATCH 079/265] Update graal import. --- graal-js/mx.graal-js/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/mx.graal-js/suite.py b/graal-js/mx.graal-js/suite.py index 2b8ce309bcc..10a225f8aa2 100644 --- a/graal-js/mx.graal-js/suite.py +++ b/graal-js/mx.graal-js/suite.py @@ -24,7 +24,7 @@ { "name" : "regex", "subdir" : True, - "version" : "940934ae7e0d3b86a9122d5b00bc2789c476a996", + "version" : "09b9192b4d06f7f6aa986af657d9a34ec82351fe", "urls" : [ {"url" : "https://github.com/oracle/graal.git", "kind" : "git"}, ] From bdb3f2cbf49cdcbcd6611d258e7356a4ddacbebc Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 5 Jul 2024 21:03:41 +0000 Subject: [PATCH 080/265] Sync CI files. --- common.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/common.json b/common.json index efedd632db4..f0a5e51d3cc 100644 --- a/common.json +++ b/common.json @@ -4,11 +4,11 @@ "Jsonnet files should not include this file directly but use ci/common.jsonnet instead." ], - "mx_version": "7.27.1", + "mx_version": "7.27.5", "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { - "galahad-jdk": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+2-53", "platformspecific": true, "extrabundles": ["static-libs"]}, + "galahad-jdk": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+5-437", "platformspecific": true, "extrabundles": ["static-libs"]}, "oraclejdk11": {"name": "jpg-jdk", "version": "11.0.11", "build_id": "jdk-11.0.11+9", "platformspecific": true, "extrabundles": ["static-libs"] }, @@ -45,13 +45,13 @@ "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.2+13-jvmci-23.1-b33-sulong", "platformspecific": true }, "graalvm-ee-21": {"name": "graalvm-java21", "version": "23.1.3", "platformspecific": true }, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+3", "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+3-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+3-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+3-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+3-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+3-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+3-jvmci-b01-sulong", "platformspecific": true } + "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+4", "platformspecific": true, "extrabundles": ["static-libs"]}, + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+4-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+4-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+4-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+4-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+4-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+4-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { From 15b39c387843177e6d385cf0118aa34cce4c3fcd Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Sun, 7 Jul 2024 19:04:04 +0200 Subject: [PATCH 081/265] Adding a note about the limited usage of Error.prepareStackTrace/stackTraceLimit into change-log. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75c52223e40..cfdbf3516a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ See [release calendar](https://www.graalvm.org/release-calendar/) for release da ## Version 24.2.0 * Implemented the [`Promise.try`](https://github.com/tc39/proposal-promise-try) proposal. It is available in ECMAScript staging mode (`--js.ecmascript-version=staging`). +* Usage of non-standard extensions `Error.prepareStackTrace` and `Error.stackTraceLimit` has been limited to `js.v8-compat` mode only. ## Version 24.1.0 * ECMAScript 2024 mode/features enabled by default. From 974e00f6f6cfe8cd8fadb2f90fc8e34edc0c0f79 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Mon, 8 Jul 2024 13:18:10 +0200 Subject: [PATCH 082/265] Removing the problematic parts of string_dedent test. --- .../js/string_dedent.js | 31 ------------------- 1 file changed, 31 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js.test/js/string_dedent.js b/graal-js/src/com.oracle.truffle.js.test/js/string_dedent.js index aef1134b55f..12c1460e732 100644 --- a/graal-js/src/com.oracle.truffle.js.test/js/string_dedent.js +++ b/graal-js/src/com.oracle.truffle.js.test/js/string_dedent.js @@ -172,34 +172,3 @@ assertSame(String.dedent({raw: ['\n\\', '\\', '\n\\\n']}, 6, 9, 'STOP'), 'undefi // Missing substitutions assertSame(String.dedent({raw: ['\n{', '}\n']}), "{}"); assertSame(String.dedent({raw: ['\n{', ',', '}\n']}), "{,}"); - -(function testDedentedCacheLookupWithPrimitiveRawValue() { - class NotSameIdentityError extends Error {} - - let expectedLength; - let first; - function interceptRaw(template, ...substitutions) { - if (!first) { - first = template; - } else if (template !== first) { - throw new NotSameIdentityError(`expected same identity`); - } - if (template.length !== expectedLength) { - throw new Error(`unexpected length: ${template.length} !== ${expectedLength}`); - } - return String.raw(template, ...substitutions); - } - - expectedLength = 4; - let value = '\na'; - assertSame('ab', String.dedent(interceptRaw)({raw: '\nab\n'})); - assertSame('ab', String.dedent(interceptRaw)({raw: value.concat('b\n')})); - - expectedLength = 1; - Number.prototype.length = 1; - Number.prototype[0] = `\nno\n`; - first = undefined; - assertSame('no', String.dedent(interceptRaw)({raw: 9001})); - assertSame('no', String.dedent(interceptRaw)({raw: Math.ceil(9000.5 + Math.random() / 3)})); - assertThrows(() => String.dedent(interceptRaw)({raw: 9000}), NotSameIdentityError); -})(); From 9cd8076ea0cc3d5ab46a481496646e5035cdae95 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 2 Jul 2024 13:23:32 +0200 Subject: [PATCH 083/265] Include wasm in maven-deploy gate. --- graal-js/ci.jsonnet | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graal-js/ci.jsonnet b/graal-js/ci.jsonnet index 0f406ddff76..63bbbc34243 100644 --- a/graal-js/ci.jsonnet +++ b/graal-js/ci.jsonnet @@ -60,8 +60,8 @@ local ci = import '../ci.jsonnet'; run+: [ ['mx', 'build'], ['mx', '-v', 'maven-deploy', '--suppress-javadoc', '--validate', 'full', '--licenses', 'UPL,MIT', '--dry-run', 'ossrh', 'https://this-is-only-a-test'], - ['mx', '-p', '../../graal/vm', '--dynamicimports', '/tools,/compiler,/graal-js', 'build'], - ['mx', '-p', '../../graal/vm', '--dynamicimports', '/tools,/regex,/compiler,/truffle,/sdk,/graal-js', 'maven-deploy', '--suppress-javadoc', '--all-suites', '--version-string', 'GATE'], + ['mx', '-p', '../../graal/vm', '--dynamicimports', '/tools,/compiler,/graal-js,/wasm', 'build'], + ['mx', '-p', '../../graal/vm', '--dynamicimports', '/tools,/regex,/compiler,/truffle,/sdk,/graal-js,/wasm', 'maven-deploy', '--suppress-javadoc', '--all-suites', '--version-string', 'GATE'], ['cd', 'test/maven-demo'], ['mvn', '-Dgraalvm.version=GATE', '--batch-mode', 'package'], ['mvn', '-Dgraalvm.version=GATE', '--batch-mode', 'exec:exec'], From 3f932fbf8f5f17e2ee13645cf127b53148f12009 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 27 Jun 2024 02:28:38 +0200 Subject: [PATCH 084/265] Add maven downloader to (node)js jvm standalone. --- .../graalvm_launchers/js-polyglot-get | 79 +++++++++++++++++++ .../graalvm_launchers/js-polyglot-get.cmd | 73 +++++++++++++++++ graal-js/mx.graal-js/mx_graal_js.py | 1 + graal-js/mx.graal-js/suite.py | 4 + .../graalvm_launchers/node-polyglot-get | 79 +++++++++++++++++++ .../graalvm_launchers/node-polyglot-get.cmd | 73 +++++++++++++++++ .../mx.graal-nodejs/mx_graal_nodejs.py | 2 + graal-nodejs/mx.graal-nodejs/suite.py | 1 + 8 files changed, 312 insertions(+) create mode 100755 graal-js/mx.graal-js/graalvm_launchers/js-polyglot-get create mode 100644 graal-js/mx.graal-js/graalvm_launchers/js-polyglot-get.cmd create mode 100755 graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get create mode 100644 graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get.cmd diff --git a/graal-js/mx.graal-js/graalvm_launchers/js-polyglot-get b/graal-js/mx.graal-js/graalvm_launchers/js-polyglot-get new file mode 100755 index 00000000000..36012fab5de --- /dev/null +++ b/graal-js/mx.graal-js/graalvm_launchers/js-polyglot-get @@ -0,0 +1,79 @@ +#!/usr/bin/env bash + +source="${BASH_SOURCE[0]}" +while [ -h "$source" ] ; do + prev_source="$source" + source="$(readlink "$source")"; + if [[ "$source" != /* ]]; then + # if the link was relative, it was relative to where it came from + dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" + source="$dir/$source" + fi +done + +bin_dir="$( cd -P "$( dirname "$source" )" && pwd )" +parent_dir="$( dirname "$bin_dir" )" + +if [ ! -x "${parent_dir}/jvm/bin/java" ]; then + echo "Error: ${parent_dir}/jvm/bin/java not found. $(basename "$0") is not available for the native standalone." + exit 1 +fi + +MAIN_ARGS=() +PRE_ARGS=() + +HAS_OUTPUTDIR=0 +HAS_VERSION=0 + +for opt in "${@:1}"; do + case "${opt}" in + -o) + HAS_OUTPUTDIR=1 + MAIN_ARGS+=("${opt}") ;; + -v) + HAS_VERSION=1 + MAIN_ARGS+=("${opt}") ;; + *) + MAIN_ARGS+=("${opt}") ;; + esac +done + +if [ $HAS_OUTPUTDIR -eq 0 ]; then + # Set default output dir. + PRE_ARGS+=("-o") + PRE_ARGS+=("${parent_dir}/modules") +fi +if [ $HAS_VERSION -eq 0 ]; then + # Read GRAALVM_VERSION property from "release" file. + if [ -f "${parent_dir}/release" ]; then + while IFS='=' read -r propertyName propertyValue + do + if [[ "${propertyName}" == "GRAALVM_VERSION" ]]; then + GRAALVM_VERSION="${propertyValue}" + break + fi + done < "${parent_dir}/release" + fi + + # Unquote version string, if wrapped in double quotes. + if [[ "${GRAALVM_VERSION}" == \"*\" ]]; then + GRAALVM_VERSION=${GRAALVM_VERSION#\"} # remove leading quote + GRAALVM_VERSION=${GRAALVM_VERSION%\"} # remove trailing quote + fi + + # If GRAALVM_VERSION is not empty, set default version. + if [ -n "${GRAALVM_VERSION}" ]; then + PRE_ARGS+=("-v") + PRE_ARGS+=("${GRAALVM_VERSION}") + fi +fi +# Treat single non-option argument as artifact id. +if [[ $# -eq 1 && "$1" != -* ]]; then + PRE_ARGS+=("-a") +fi + +if [ "${VERBOSE_GRAALVM_LAUNCHERS}" == "true" ]; then + set -x +fi + +exec "${parent_dir}/jvm/bin/java" "-p" "${parent_dir}/modules" "-m" "org.graalvm.maven.downloader/org.graalvm.maven.downloader.Main" "${PRE_ARGS[@]}" "${MAIN_ARGS[@]}" diff --git a/graal-js/mx.graal-js/graalvm_launchers/js-polyglot-get.cmd b/graal-js/mx.graal-js/graalvm_launchers/js-polyglot-get.cmd new file mode 100644 index 00000000000..868a077cc23 --- /dev/null +++ b/graal-js/mx.graal-js/graalvm_launchers/js-polyglot-get.cmd @@ -0,0 +1,73 @@ +@echo off +setlocal enabledelayedexpansion + +call :dirname "%~0" bin_dir +call :dirname "%bin_dir%" parent_dir + +if not exist "%parent_dir%/jvm/bin/java.exe" ( + echo "Error: %parent_dir%/jvm/bin/java.exe not found. %~nx0 is not available for the native standalone." + exit /b 1 +) + +set MAIN_ARGS= +set PRE_ARGS= + +set HAS_OUTPUTDIR=0 +set HAS_VERSION=0 + +for %%a in (%*) do ( + if "%%~a"=="-o" ( + set HAS_OUTPUTDIR=1 + set "MAIN_ARGS=!MAIN_ARGS! %%a" + ) else if "%%~a"=="-v" ( + set HAS_VERSION=1 + set "MAIN_ARGS=!MAIN_ARGS! %%a" + ) else ( + set "MAIN_ARGS=!MAIN_ARGS! %%a" + ) +) + +if %HAS_OUTPUTDIR%==0 ( + rem Set default output dir. + set "PRE_ARGS=-o %parent_dir%/modules" +) + +if %HAS_VERSION%==0 ( + if exist "%parent_dir%/release" ( + for /f "tokens=1,2 delims==" %%a in (%parent_dir%/release) do ( + if "%%a"=="GRAALVM_VERSION" ( + set "GRAALVM_VERSION=%%b" + ) + ) + ) + + if defined GRAALVM_VERSION ( + rem Remove double quotes from version string. + set "GRAALVM_VERSION=!GRAALVM_VERSION:"=!" + rem Set default version. + set "PRE_ARGS=!PRE_ARGS! -v !GRAALVM_VERSION!" + ) +) + +rem Treat single non-option argument as artifact id. +if not "%~1"=="" if "%~2"=="" ( + set "start=%~1" + set "start=!start:~0,1!" + if not "!start!"=="-" ( + set "PRE_ARGS=!PRE_ARGS! -a" + ) +) + +if "%VERBOSE_GRAALVM_LAUNCHERS%"=="true" echo on + +"%parent_dir%/jvm/bin/java.exe" -p "%parent_dir%/modules" -m "org.graalvm.maven.downloader/org.graalvm.maven.downloader.Main" %PRE_ARGS% %MAIN_ARGS% + +@echo off +exit /b %errorlevel% + +:dirname file output + setlocal + set "dir=%~dp1" + set "dir=%dir:~0,-1%" + endlocal & set "%2=%dir%" + exit /b 0 diff --git a/graal-js/mx.graal-js/mx_graal_js.py b/graal-js/mx.graal-js/mx_graal_js.py index 906cbc7db60..a035e3be7c2 100644 --- a/graal-js/mx.graal-js/mx_graal_js.py +++ b/graal-js/mx.graal-js/mx_graal_js.py @@ -548,6 +548,7 @@ def mx_register_dynamic_suite_constituents(register_project, register_distributi ], truffle_jars=[ 'graal-js:GRAALJS', + 'sdk:MAVEN_DOWNLOADER', ], support_distributions=[ 'graal-js:GRAALJS_GRAALVM_SUPPORT', diff --git a/graal-js/mx.graal-js/suite.py b/graal-js/mx.graal-js/suite.py index 10a225f8aa2..0bf408aec4e 100644 --- a/graal-js/mx.graal-js/suite.py +++ b/graal-js/mx.graal-js/suite.py @@ -690,12 +690,16 @@ "GRAALJS_GRAALVM_SUPPORT" : { "native" : True, + "platformDependent" : True, "description" : "Graal.js support distribution for the GraalVM", "layout" : { "native-image.properties": "file:mx.graal-js/native-image.properties", "./": [ "file:README.md", ], + "bin/": [ + "file:mx.graal-js/graalvm_launchers/", + ] }, }, diff --git a/graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get b/graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get new file mode 100755 index 00000000000..36012fab5de --- /dev/null +++ b/graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get @@ -0,0 +1,79 @@ +#!/usr/bin/env bash + +source="${BASH_SOURCE[0]}" +while [ -h "$source" ] ; do + prev_source="$source" + source="$(readlink "$source")"; + if [[ "$source" != /* ]]; then + # if the link was relative, it was relative to where it came from + dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" + source="$dir/$source" + fi +done + +bin_dir="$( cd -P "$( dirname "$source" )" && pwd )" +parent_dir="$( dirname "$bin_dir" )" + +if [ ! -x "${parent_dir}/jvm/bin/java" ]; then + echo "Error: ${parent_dir}/jvm/bin/java not found. $(basename "$0") is not available for the native standalone." + exit 1 +fi + +MAIN_ARGS=() +PRE_ARGS=() + +HAS_OUTPUTDIR=0 +HAS_VERSION=0 + +for opt in "${@:1}"; do + case "${opt}" in + -o) + HAS_OUTPUTDIR=1 + MAIN_ARGS+=("${opt}") ;; + -v) + HAS_VERSION=1 + MAIN_ARGS+=("${opt}") ;; + *) + MAIN_ARGS+=("${opt}") ;; + esac +done + +if [ $HAS_OUTPUTDIR -eq 0 ]; then + # Set default output dir. + PRE_ARGS+=("-o") + PRE_ARGS+=("${parent_dir}/modules") +fi +if [ $HAS_VERSION -eq 0 ]; then + # Read GRAALVM_VERSION property from "release" file. + if [ -f "${parent_dir}/release" ]; then + while IFS='=' read -r propertyName propertyValue + do + if [[ "${propertyName}" == "GRAALVM_VERSION" ]]; then + GRAALVM_VERSION="${propertyValue}" + break + fi + done < "${parent_dir}/release" + fi + + # Unquote version string, if wrapped in double quotes. + if [[ "${GRAALVM_VERSION}" == \"*\" ]]; then + GRAALVM_VERSION=${GRAALVM_VERSION#\"} # remove leading quote + GRAALVM_VERSION=${GRAALVM_VERSION%\"} # remove trailing quote + fi + + # If GRAALVM_VERSION is not empty, set default version. + if [ -n "${GRAALVM_VERSION}" ]; then + PRE_ARGS+=("-v") + PRE_ARGS+=("${GRAALVM_VERSION}") + fi +fi +# Treat single non-option argument as artifact id. +if [[ $# -eq 1 && "$1" != -* ]]; then + PRE_ARGS+=("-a") +fi + +if [ "${VERBOSE_GRAALVM_LAUNCHERS}" == "true" ]; then + set -x +fi + +exec "${parent_dir}/jvm/bin/java" "-p" "${parent_dir}/modules" "-m" "org.graalvm.maven.downloader/org.graalvm.maven.downloader.Main" "${PRE_ARGS[@]}" "${MAIN_ARGS[@]}" diff --git a/graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get.cmd b/graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get.cmd new file mode 100644 index 00000000000..868a077cc23 --- /dev/null +++ b/graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get.cmd @@ -0,0 +1,73 @@ +@echo off +setlocal enabledelayedexpansion + +call :dirname "%~0" bin_dir +call :dirname "%bin_dir%" parent_dir + +if not exist "%parent_dir%/jvm/bin/java.exe" ( + echo "Error: %parent_dir%/jvm/bin/java.exe not found. %~nx0 is not available for the native standalone." + exit /b 1 +) + +set MAIN_ARGS= +set PRE_ARGS= + +set HAS_OUTPUTDIR=0 +set HAS_VERSION=0 + +for %%a in (%*) do ( + if "%%~a"=="-o" ( + set HAS_OUTPUTDIR=1 + set "MAIN_ARGS=!MAIN_ARGS! %%a" + ) else if "%%~a"=="-v" ( + set HAS_VERSION=1 + set "MAIN_ARGS=!MAIN_ARGS! %%a" + ) else ( + set "MAIN_ARGS=!MAIN_ARGS! %%a" + ) +) + +if %HAS_OUTPUTDIR%==0 ( + rem Set default output dir. + set "PRE_ARGS=-o %parent_dir%/modules" +) + +if %HAS_VERSION%==0 ( + if exist "%parent_dir%/release" ( + for /f "tokens=1,2 delims==" %%a in (%parent_dir%/release) do ( + if "%%a"=="GRAALVM_VERSION" ( + set "GRAALVM_VERSION=%%b" + ) + ) + ) + + if defined GRAALVM_VERSION ( + rem Remove double quotes from version string. + set "GRAALVM_VERSION=!GRAALVM_VERSION:"=!" + rem Set default version. + set "PRE_ARGS=!PRE_ARGS! -v !GRAALVM_VERSION!" + ) +) + +rem Treat single non-option argument as artifact id. +if not "%~1"=="" if "%~2"=="" ( + set "start=%~1" + set "start=!start:~0,1!" + if not "!start!"=="-" ( + set "PRE_ARGS=!PRE_ARGS! -a" + ) +) + +if "%VERBOSE_GRAALVM_LAUNCHERS%"=="true" echo on + +"%parent_dir%/jvm/bin/java.exe" -p "%parent_dir%/modules" -m "org.graalvm.maven.downloader/org.graalvm.maven.downloader.Main" %PRE_ARGS% %MAIN_ARGS% + +@echo off +exit /b %errorlevel% + +:dirname file output + setlocal + set "dir=%~dp1" + set "dir=%dir:~0,-1%" + endlocal & set "%2=%dir%" + exit /b 0 diff --git a/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py b/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py index 9c84cec5e50..ac90650126a 100644 --- a/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py +++ b/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py @@ -632,6 +632,7 @@ def _is_wasm_available(): ], truffle_jars=[ 'graal-nodejs:TRUFFLENODE', + 'sdk:MAVEN_DOWNLOADER', *(['wasm:WASM'] if _is_wasm_available() else []), ], support_distributions=[ @@ -641,6 +642,7 @@ def _is_wasm_available(): 'bin/', 'bin/', 'bin/', + 'bin/', ], polyglot_lib_build_args=['--language:nodejs'], polyglot_lib_jar_dependencies=['graal-nodejs:TRUFFLENODE'], diff --git a/graal-nodejs/mx.graal-nodejs/suite.py b/graal-nodejs/mx.graal-nodejs/suite.py index 52171d69cc1..504ba7991f3 100644 --- a/graal-nodejs/mx.graal-nodejs/suite.py +++ b/graal-nodejs/mx.graal-nodejs/suite.py @@ -163,6 +163,7 @@ "dependency:trufflenodeNative/Release/", "file:mx.graal-nodejs/graalvm_launchers/", "file:mx.graal-nodejs/graalvm_launchers/", + "file:mx.graal-nodejs/graalvm_launchers/", ], }, "os" : { From 8bdbac02484a3a5ac7e8e35122394898237adaf7 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 8 Jul 2024 19:16:37 +0200 Subject: [PATCH 085/265] Move default argument handling to org.graalvm.maven.downloader. --- .../graalvm_launchers/js-polyglot-get | 55 +------------------ .../graalvm_launchers/js-polyglot-get.cmd | 51 +---------------- .../graalvm_launchers/node-polyglot-get | 55 +------------------ .../graalvm_launchers/node-polyglot-get.cmd | 51 +---------------- 4 files changed, 4 insertions(+), 208 deletions(-) diff --git a/graal-js/mx.graal-js/graalvm_launchers/js-polyglot-get b/graal-js/mx.graal-js/graalvm_launchers/js-polyglot-get index 36012fab5de..9dc71c888e7 100755 --- a/graal-js/mx.graal-js/graalvm_launchers/js-polyglot-get +++ b/graal-js/mx.graal-js/graalvm_launchers/js-polyglot-get @@ -19,61 +19,8 @@ if [ ! -x "${parent_dir}/jvm/bin/java" ]; then exit 1 fi -MAIN_ARGS=() -PRE_ARGS=() - -HAS_OUTPUTDIR=0 -HAS_VERSION=0 - -for opt in "${@:1}"; do - case "${opt}" in - -o) - HAS_OUTPUTDIR=1 - MAIN_ARGS+=("${opt}") ;; - -v) - HAS_VERSION=1 - MAIN_ARGS+=("${opt}") ;; - *) - MAIN_ARGS+=("${opt}") ;; - esac -done - -if [ $HAS_OUTPUTDIR -eq 0 ]; then - # Set default output dir. - PRE_ARGS+=("-o") - PRE_ARGS+=("${parent_dir}/modules") -fi -if [ $HAS_VERSION -eq 0 ]; then - # Read GRAALVM_VERSION property from "release" file. - if [ -f "${parent_dir}/release" ]; then - while IFS='=' read -r propertyName propertyValue - do - if [[ "${propertyName}" == "GRAALVM_VERSION" ]]; then - GRAALVM_VERSION="${propertyValue}" - break - fi - done < "${parent_dir}/release" - fi - - # Unquote version string, if wrapped in double quotes. - if [[ "${GRAALVM_VERSION}" == \"*\" ]]; then - GRAALVM_VERSION=${GRAALVM_VERSION#\"} # remove leading quote - GRAALVM_VERSION=${GRAALVM_VERSION%\"} # remove trailing quote - fi - - # If GRAALVM_VERSION is not empty, set default version. - if [ -n "${GRAALVM_VERSION}" ]; then - PRE_ARGS+=("-v") - PRE_ARGS+=("${GRAALVM_VERSION}") - fi -fi -# Treat single non-option argument as artifact id. -if [[ $# -eq 1 && "$1" != -* ]]; then - PRE_ARGS+=("-a") -fi - if [ "${VERBOSE_GRAALVM_LAUNCHERS}" == "true" ]; then set -x fi -exec "${parent_dir}/jvm/bin/java" "-p" "${parent_dir}/modules" "-m" "org.graalvm.maven.downloader/org.graalvm.maven.downloader.Main" "${PRE_ARGS[@]}" "${MAIN_ARGS[@]}" +exec "${parent_dir}/jvm/bin/java" "-p" "${parent_dir}/modules" "-m" "org.graalvm.maven.downloader/org.graalvm.maven.downloader.Main" "$@" diff --git a/graal-js/mx.graal-js/graalvm_launchers/js-polyglot-get.cmd b/graal-js/mx.graal-js/graalvm_launchers/js-polyglot-get.cmd index 868a077cc23..9e28460d12b 100644 --- a/graal-js/mx.graal-js/graalvm_launchers/js-polyglot-get.cmd +++ b/graal-js/mx.graal-js/graalvm_launchers/js-polyglot-get.cmd @@ -9,58 +9,9 @@ if not exist "%parent_dir%/jvm/bin/java.exe" ( exit /b 1 ) -set MAIN_ARGS= -set PRE_ARGS= - -set HAS_OUTPUTDIR=0 -set HAS_VERSION=0 - -for %%a in (%*) do ( - if "%%~a"=="-o" ( - set HAS_OUTPUTDIR=1 - set "MAIN_ARGS=!MAIN_ARGS! %%a" - ) else if "%%~a"=="-v" ( - set HAS_VERSION=1 - set "MAIN_ARGS=!MAIN_ARGS! %%a" - ) else ( - set "MAIN_ARGS=!MAIN_ARGS! %%a" - ) -) - -if %HAS_OUTPUTDIR%==0 ( - rem Set default output dir. - set "PRE_ARGS=-o %parent_dir%/modules" -) - -if %HAS_VERSION%==0 ( - if exist "%parent_dir%/release" ( - for /f "tokens=1,2 delims==" %%a in (%parent_dir%/release) do ( - if "%%a"=="GRAALVM_VERSION" ( - set "GRAALVM_VERSION=%%b" - ) - ) - ) - - if defined GRAALVM_VERSION ( - rem Remove double quotes from version string. - set "GRAALVM_VERSION=!GRAALVM_VERSION:"=!" - rem Set default version. - set "PRE_ARGS=!PRE_ARGS! -v !GRAALVM_VERSION!" - ) -) - -rem Treat single non-option argument as artifact id. -if not "%~1"=="" if "%~2"=="" ( - set "start=%~1" - set "start=!start:~0,1!" - if not "!start!"=="-" ( - set "PRE_ARGS=!PRE_ARGS! -a" - ) -) - if "%VERBOSE_GRAALVM_LAUNCHERS%"=="true" echo on -"%parent_dir%/jvm/bin/java.exe" -p "%parent_dir%/modules" -m "org.graalvm.maven.downloader/org.graalvm.maven.downloader.Main" %PRE_ARGS% %MAIN_ARGS% +"%parent_dir%/jvm/bin/java.exe" -p "%parent_dir%/modules" -m "org.graalvm.maven.downloader/org.graalvm.maven.downloader.Main" %* @echo off exit /b %errorlevel% diff --git a/graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get b/graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get index 36012fab5de..9dc71c888e7 100755 --- a/graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get +++ b/graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get @@ -19,61 +19,8 @@ if [ ! -x "${parent_dir}/jvm/bin/java" ]; then exit 1 fi -MAIN_ARGS=() -PRE_ARGS=() - -HAS_OUTPUTDIR=0 -HAS_VERSION=0 - -for opt in "${@:1}"; do - case "${opt}" in - -o) - HAS_OUTPUTDIR=1 - MAIN_ARGS+=("${opt}") ;; - -v) - HAS_VERSION=1 - MAIN_ARGS+=("${opt}") ;; - *) - MAIN_ARGS+=("${opt}") ;; - esac -done - -if [ $HAS_OUTPUTDIR -eq 0 ]; then - # Set default output dir. - PRE_ARGS+=("-o") - PRE_ARGS+=("${parent_dir}/modules") -fi -if [ $HAS_VERSION -eq 0 ]; then - # Read GRAALVM_VERSION property from "release" file. - if [ -f "${parent_dir}/release" ]; then - while IFS='=' read -r propertyName propertyValue - do - if [[ "${propertyName}" == "GRAALVM_VERSION" ]]; then - GRAALVM_VERSION="${propertyValue}" - break - fi - done < "${parent_dir}/release" - fi - - # Unquote version string, if wrapped in double quotes. - if [[ "${GRAALVM_VERSION}" == \"*\" ]]; then - GRAALVM_VERSION=${GRAALVM_VERSION#\"} # remove leading quote - GRAALVM_VERSION=${GRAALVM_VERSION%\"} # remove trailing quote - fi - - # If GRAALVM_VERSION is not empty, set default version. - if [ -n "${GRAALVM_VERSION}" ]; then - PRE_ARGS+=("-v") - PRE_ARGS+=("${GRAALVM_VERSION}") - fi -fi -# Treat single non-option argument as artifact id. -if [[ $# -eq 1 && "$1" != -* ]]; then - PRE_ARGS+=("-a") -fi - if [ "${VERBOSE_GRAALVM_LAUNCHERS}" == "true" ]; then set -x fi -exec "${parent_dir}/jvm/bin/java" "-p" "${parent_dir}/modules" "-m" "org.graalvm.maven.downloader/org.graalvm.maven.downloader.Main" "${PRE_ARGS[@]}" "${MAIN_ARGS[@]}" +exec "${parent_dir}/jvm/bin/java" "-p" "${parent_dir}/modules" "-m" "org.graalvm.maven.downloader/org.graalvm.maven.downloader.Main" "$@" diff --git a/graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get.cmd b/graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get.cmd index 868a077cc23..9e28460d12b 100644 --- a/graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get.cmd +++ b/graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get.cmd @@ -9,58 +9,9 @@ if not exist "%parent_dir%/jvm/bin/java.exe" ( exit /b 1 ) -set MAIN_ARGS= -set PRE_ARGS= - -set HAS_OUTPUTDIR=0 -set HAS_VERSION=0 - -for %%a in (%*) do ( - if "%%~a"=="-o" ( - set HAS_OUTPUTDIR=1 - set "MAIN_ARGS=!MAIN_ARGS! %%a" - ) else if "%%~a"=="-v" ( - set HAS_VERSION=1 - set "MAIN_ARGS=!MAIN_ARGS! %%a" - ) else ( - set "MAIN_ARGS=!MAIN_ARGS! %%a" - ) -) - -if %HAS_OUTPUTDIR%==0 ( - rem Set default output dir. - set "PRE_ARGS=-o %parent_dir%/modules" -) - -if %HAS_VERSION%==0 ( - if exist "%parent_dir%/release" ( - for /f "tokens=1,2 delims==" %%a in (%parent_dir%/release) do ( - if "%%a"=="GRAALVM_VERSION" ( - set "GRAALVM_VERSION=%%b" - ) - ) - ) - - if defined GRAALVM_VERSION ( - rem Remove double quotes from version string. - set "GRAALVM_VERSION=!GRAALVM_VERSION:"=!" - rem Set default version. - set "PRE_ARGS=!PRE_ARGS! -v !GRAALVM_VERSION!" - ) -) - -rem Treat single non-option argument as artifact id. -if not "%~1"=="" if "%~2"=="" ( - set "start=%~1" - set "start=!start:~0,1!" - if not "!start!"=="-" ( - set "PRE_ARGS=!PRE_ARGS! -a" - ) -) - if "%VERBOSE_GRAALVM_LAUNCHERS%"=="true" echo on -"%parent_dir%/jvm/bin/java.exe" -p "%parent_dir%/modules" -m "org.graalvm.maven.downloader/org.graalvm.maven.downloader.Main" %PRE_ARGS% %MAIN_ARGS% +"%parent_dir%/jvm/bin/java.exe" -p "%parent_dir%/modules" -m "org.graalvm.maven.downloader/org.graalvm.maven.downloader.Main" %* @echo off exit /b %errorlevel% From 01ec37efa5e01ad9dce6a86d7d5770d7d76c64b7 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 1 Jul 2024 20:02:04 +0200 Subject: [PATCH 086/265] Add maven downloader smoke test. --- graal-js/ci.jsonnet | 2 ++ graal-nodejs/ci.jsonnet | 2 ++ 2 files changed, 4 insertions(+) diff --git a/graal-js/ci.jsonnet b/graal-js/ci.jsonnet index 63bbbc34243..09e36e8901c 100644 --- a/graal-js/ci.jsonnet +++ b/graal-js/ci.jsonnet @@ -52,6 +52,8 @@ local ci = import '../ci.jsonnet'; ['set-export', 'STANDALONE_HOME', ['mx', '--quiet', 'standalone-home', 'js', '--type=jvm']], ['${STANDALONE_HOME}/bin/js', '--jvm', '-e', "print('hello:' + Array.from(new Array(10), (x,i) => i*i ).join('|'))"], ['${STANDALONE_HOME}/bin/js', '--jvm', '../../js-benchmarks/harness.js', '--', '../../js-benchmarks/octane-richards.js', '--show-warmup'], + # maven-downloader smoke test + ['VERBOSE_GRAALVM_LAUNCHERS=true', '${STANDALONE_HOME}/bin/js-polyglot-get', '-o', 'maven downloader output', '-a', 'wasm', '-v', '23.1.3'], ], timelimit: '30:00', }, diff --git a/graal-nodejs/ci.jsonnet b/graal-nodejs/ci.jsonnet index 21d9944faa6..12df981e4fc 100644 --- a/graal-nodejs/ci.jsonnet +++ b/graal-nodejs/ci.jsonnet @@ -52,6 +52,8 @@ local cicommon = import '../ci/common.jsonnet'; ['set-export', 'STANDALONE_HOME', ['mx', '--quiet', 'standalone-home', 'nodejs', '--type=jvm']], ['${STANDALONE_HOME}/bin/node', '-e', "console.log('Hello, World!')"], ['${STANDALONE_HOME}/bin/npm', '--version'], + # maven-downloader smoke test + ['VERBOSE_GRAALVM_LAUNCHERS=true', '${STANDALONE_HOME}/bin/node-polyglot-get', '-o', 'maven downloader output', '-a', 'wasm', '-v', '23.1.3'], ] + (if std.find('lib:graal-nodejs', super.nativeimages) != [] then ([ ['set-export', 'STANDALONE_HOME', ['mx', '--quiet', 'standalone-home', 'nodejs', '--type=native']], ['${STANDALONE_HOME}/bin/node', '-e', "console.log('Hello, World!')"], From e89a5d008ed2dd2e893ca41d39ada4da73b0513e Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Tue, 9 Jul 2024 00:35:37 +0000 Subject: [PATCH 087/265] Update graal import. --- graal-js/mx.graal-js/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/mx.graal-js/suite.py b/graal-js/mx.graal-js/suite.py index 10a225f8aa2..00a9e7cd8ee 100644 --- a/graal-js/mx.graal-js/suite.py +++ b/graal-js/mx.graal-js/suite.py @@ -24,7 +24,7 @@ { "name" : "regex", "subdir" : True, - "version" : "09b9192b4d06f7f6aa986af657d9a34ec82351fe", + "version" : "9d02a101054894edf80d1dfc1fc1960ae3aef772", "urls" : [ {"url" : "https://github.com/oracle/graal.git", "kind" : "git"}, ] From 7cea1cfff07594f941563021df4ddfc788d9b476 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Tue, 9 Jul 2024 00:35:38 +0000 Subject: [PATCH 088/265] Sync CI files. --- common.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/common.json b/common.json index f0a5e51d3cc..18b166ffc31 100644 --- a/common.json +++ b/common.json @@ -45,13 +45,13 @@ "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.2+13-jvmci-23.1-b33-sulong", "platformspecific": true }, "graalvm-ee-21": {"name": "graalvm-java21", "version": "23.1.3", "platformspecific": true }, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+4", "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+4-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+4-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+4-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+4-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+4-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+4-jvmci-b01-sulong", "platformspecific": true } + "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+5", "platformspecific": true, "extrabundles": ["static-libs"]}, + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+5-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+5-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+5-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+5-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+5-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+5-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { From f0f3dc6dfc0e1be003769357df01e60f5c7c4068 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Tue, 9 Jul 2024 11:30:41 +0200 Subject: [PATCH 089/265] Enabling Error.stackTraceLimit in MLE mode. --- .../truffle/js/nodes/access/ErrorStackTraceLimitNode.java | 2 +- .../src/com/oracle/truffle/js/runtime/JSException.java | 2 +- .../src/com/oracle/truffle/js/runtime/JSRealm.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ErrorStackTraceLimitNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ErrorStackTraceLimitNode.java index 31212b67944..2ba0a2f6c25 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ErrorStackTraceLimitNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ErrorStackTraceLimitNode.java @@ -70,7 +70,7 @@ protected final int doInt( @Cached IsNumberNode isNumber, @Cached JSToIntegerAsLongNode toInteger) { JSContext context = getJSContext(); - if (context.isOptionV8CompatibilityMode()) { + if (context.isOptionV8CompatibilityMode() || context.getLanguageOptions().isMLEMode()) { JSFunctionObject errorConstructor = getRealm().getErrorConstructor(JSErrorType.Error); if (JSProperty.isData(getStackTraceLimit.getPropertyFlagsOrDefault(errorConstructor, JSError.STACK_TRACE_LIMIT_PROPERTY_NAME, JSProperty.ACCESSOR))) { Object value = getStackTraceLimit.getOrDefault(errorConstructor, JSError.STACK_TRACE_LIMIT_PROPERTY_NAME, Undefined.instance); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSException.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSException.java index a07d27cb376..44b77ac4a52 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSException.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSException.java @@ -151,7 +151,7 @@ public static JSException create(JSErrorType type, String message, Throwable cau public static int getStackTraceLimit(JSRealm realm) { JSContextOptions contextOptions = realm.getContextOptions(); - if (contextOptions.isV8CompatibilityMode()) { + if (contextOptions.isV8CompatibilityMode() || contextOptions.isMLEMode()) { JSFunctionObject errorConstructor = realm.getErrorConstructor(JSErrorType.Error); DynamicObjectLibrary lib = DynamicObjectLibrary.getUncached(); if (JSProperty.isData(lib.getPropertyFlagsOrDefault(errorConstructor, JSError.STACK_TRACE_LIMIT_PROPERTY_NAME, JSProperty.ACCESSOR))) { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java index df9c651fd1c..c2e1cff5b3e 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java @@ -2256,7 +2256,7 @@ private void addGlobalGlobal() { } private void addErrorStackTraceLimit() { - if (getContextOptions().isV8CompatibilityMode()) { + if (getContextOptions().isV8CompatibilityMode() || getContextOptions().isMLEMode()) { JSObject errorConstructor = getErrorConstructor(JSErrorType.Error); JSObjectUtil.putDataProperty(errorConstructor, JSError.STACK_TRACE_LIMIT_PROPERTY_NAME, getContextOptions().getStackTraceLimit(), JSAttributes.getDefault()); } From 470ca32c6afa9605a2e3b606a24f9305e8f784c7 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 11 Jul 2024 00:33:42 +0200 Subject: [PATCH 090/265] Share identical js-polyglot-get and node-polyglot-get launcher scripts. --- .../graalvm_launchers/node-polyglot-get | 26 ------------------- .../graalvm_launchers/node-polyglot-get.cmd | 24 ----------------- graal-nodejs/mx.graal-nodejs/suite.py | 2 +- 3 files changed, 1 insertion(+), 51 deletions(-) delete mode 100755 graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get delete mode 100644 graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get.cmd diff --git a/graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get b/graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get deleted file mode 100755 index 9dc71c888e7..00000000000 --- a/graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash - -source="${BASH_SOURCE[0]}" -while [ -h "$source" ] ; do - prev_source="$source" - source="$(readlink "$source")"; - if [[ "$source" != /* ]]; then - # if the link was relative, it was relative to where it came from - dir="$( cd -P "$( dirname "$prev_source" )" && pwd )" - source="$dir/$source" - fi -done - -bin_dir="$( cd -P "$( dirname "$source" )" && pwd )" -parent_dir="$( dirname "$bin_dir" )" - -if [ ! -x "${parent_dir}/jvm/bin/java" ]; then - echo "Error: ${parent_dir}/jvm/bin/java not found. $(basename "$0") is not available for the native standalone." - exit 1 -fi - -if [ "${VERBOSE_GRAALVM_LAUNCHERS}" == "true" ]; then - set -x -fi - -exec "${parent_dir}/jvm/bin/java" "-p" "${parent_dir}/modules" "-m" "org.graalvm.maven.downloader/org.graalvm.maven.downloader.Main" "$@" diff --git a/graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get.cmd b/graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get.cmd deleted file mode 100644 index 9e28460d12b..00000000000 --- a/graal-nodejs/mx.graal-nodejs/graalvm_launchers/node-polyglot-get.cmd +++ /dev/null @@ -1,24 +0,0 @@ -@echo off -setlocal enabledelayedexpansion - -call :dirname "%~0" bin_dir -call :dirname "%bin_dir%" parent_dir - -if not exist "%parent_dir%/jvm/bin/java.exe" ( - echo "Error: %parent_dir%/jvm/bin/java.exe not found. %~nx0 is not available for the native standalone." - exit /b 1 -) - -if "%VERBOSE_GRAALVM_LAUNCHERS%"=="true" echo on - -"%parent_dir%/jvm/bin/java.exe" -p "%parent_dir%/modules" -m "org.graalvm.maven.downloader/org.graalvm.maven.downloader.Main" %* - -@echo off -exit /b %errorlevel% - -:dirname file output - setlocal - set "dir=%~dp1" - set "dir=%dir:~0,-1%" - endlocal & set "%2=%dir%" - exit /b 0 diff --git a/graal-nodejs/mx.graal-nodejs/suite.py b/graal-nodejs/mx.graal-nodejs/suite.py index 504ba7991f3..3816b391894 100644 --- a/graal-nodejs/mx.graal-nodejs/suite.py +++ b/graal-nodejs/mx.graal-nodejs/suite.py @@ -163,8 +163,8 @@ "dependency:trufflenodeNative/Release/", "file:mx.graal-nodejs/graalvm_launchers/", "file:mx.graal-nodejs/graalvm_launchers/", - "file:mx.graal-nodejs/graalvm_launchers/", ], + "bin/": "file:../graal-js/mx.graal-js/graalvm_launchers/", }, "os" : { "windows" : {}, From fa037b3f02bbc064da75dccf95bdc7c23e39220f Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 11 Jul 2024 00:46:12 +0200 Subject: [PATCH 091/265] Add PromiseRejectionTrackerTest and PromiseHookTest. --- .../js/test/runtime/PromiseHookTest.java | 87 ++++++++++ .../runtime/PromiseRejectionTrackerTest.java | 159 ++++++++++++++++++ 2 files changed, 246 insertions(+) create mode 100644 graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/runtime/PromiseHookTest.java create mode 100644 graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/runtime/PromiseRejectionTrackerTest.java diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/runtime/PromiseHookTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/runtime/PromiseHookTest.java new file mode 100644 index 00000000000..90fd0fc2976 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/runtime/PromiseHookTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.test.runtime; + +import static com.oracle.truffle.js.lang.JavaScriptLanguage.ID; +import static org.junit.Assert.assertEquals; + +import org.graalvm.polyglot.Context; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.oracle.truffle.js.lang.JavaScriptLanguage; +import com.oracle.truffle.js.runtime.JSContext; +import com.oracle.truffle.js.runtime.PromiseHook; +import com.oracle.truffle.js.runtime.objects.JSDynamicObject; +import com.oracle.truffle.js.test.JSTest; + +public class PromiseHookTest { + private Context ctx; + + @Before + public void setup() { + ctx = JSTest.newContextBuilder().build(); + } + + @After + public void tearDown() { + ctx.close(); + } + + @Test + public void testBasic() { + JSContext context = JavaScriptLanguage.getJSContext(ctx); + final int[] changes = new int[4]; + context.setPromiseHook(new PromiseHook() { + @Override + public void promiseChanged(int changeType, JSDynamicObject promise, JSDynamicObject parentPromise) { + changes[changeType]++; + } + }); + ctx.eval(ID, "Promise.resolve(42).then(() => {})"); + assertEquals(2, changes[PromiseHook.TYPE_INIT]); + assertEquals(2, changes[PromiseHook.TYPE_RESOLVE]); + assertEquals(1, changes[PromiseHook.TYPE_BEFORE]); + assertEquals(1, changes[PromiseHook.TYPE_AFTER]); + } + +} diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/runtime/PromiseRejectionTrackerTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/runtime/PromiseRejectionTrackerTest.java new file mode 100644 index 00000000000..2d3ccf3f210 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/runtime/PromiseRejectionTrackerTest.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.test.runtime; + +import static com.oracle.truffle.js.lang.JavaScriptLanguage.ID; +import static org.junit.Assert.assertEquals; + +import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.Value; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.oracle.truffle.js.lang.JavaScriptLanguage; +import com.oracle.truffle.js.runtime.JSContext; +import com.oracle.truffle.js.runtime.PromiseRejectionTracker; +import com.oracle.truffle.js.runtime.objects.JSDynamicObject; +import com.oracle.truffle.js.test.JSTest; + +public class PromiseRejectionTrackerTest { + private Context ctx; + + @Before + public void setup() { + ctx = JSTest.newContextBuilder().build(); + } + + @After + public void tearDown() { + ctx.close(); + } + + @Test + public void testBasic() { + JSContext context = JavaScriptLanguage.getJSContext(ctx); + final int[] rejected = new int[1]; + final int[] handled = new int[1]; + final int[] rejectAfterResolve = new int[1]; + final int[] resolveAfterResolve = new int[1]; + context.setPromiseRejectionTracker(new PromiseRejectionTracker() { + @Override + public void promiseRejected(JSDynamicObject promise, Object value) { + rejected[0]++; + } + + @Override + public void promiseRejectionHandled(JSDynamicObject promise) { + handled[0]++; + } + + @Override + public void promiseRejectedAfterResolved(JSDynamicObject promise, Object value) { + rejectAfterResolve[0]++; + } + + @Override + public void promiseResolvedAfterResolved(JSDynamicObject promise, Object value) { + resolveAfterResolve[0]++; + } + }); + + ctx.eval(ID, "Promise.resolve().then(() => { throw new Error(); }).catch(() => {})"); + assertEquals(0, rejected[0]); + assertEquals(0, handled[0]); + + Value promise1 = ctx.eval(ID, "Promise.reject(42)"); + assertEquals(1, rejected[0]); + + Value promise2 = ctx.eval(ID, "Promise.resolve('foo')"); + assertEquals(1, rejected[0]); + + Value promise3 = ctx.eval(ID, "new Promise((resolve, reject) => resolve('bar'))"); + assertEquals(1, rejected[0]); + + Value promise4 = ctx.eval(ID, "new Promise((resolve, reject) => reject('baz'))"); + assertEquals(2, rejected[0]); + + Value promise5 = ctx.eval(ID, "new Promise((resolve, reject) => { throw new Error() })"); + assertEquals(3, rejected[0]); + assertEquals(0, handled[0]); + + Value catchAll = ctx.eval(ID, "promise => promise.catch(() => {})"); + catchAll.execute(promise1); + assertEquals(1, handled[0]); + + catchAll.execute(promise2); + assertEquals(1, handled[0]); + + catchAll.execute(promise3); + assertEquals(1, handled[0]); + + catchAll.execute(promise4); + assertEquals(2, handled[0]); + + catchAll.execute(promise5); + assertEquals(3, handled[0]); + + catchAll.execute(promise5); + assertEquals(3, handled[0]); + assertEquals(3, rejected[0]); + + assertEquals(0, rejectAfterResolve[0]); + assertEquals(0, resolveAfterResolve[0]); + ctx.eval(ID, "new Promise((resolve, reject) => { resolve('foo'); resolve('bar'); })"); + assertEquals(0, rejectAfterResolve[0]); + assertEquals(1, resolveAfterResolve[0]); + + ctx.eval(ID, "new Promise((resolve, reject) => { resolve('foo'); reject('bar'); })"); + assertEquals(1, rejectAfterResolve[0]); + assertEquals(1, resolveAfterResolve[0]); + + ctx.eval(ID, "new Promise((resolve, reject) => { reject('foo'); reject('bar'); })"); + assertEquals(2, rejectAfterResolve[0]); + assertEquals(1, resolveAfterResolve[0]); + + ctx.eval(ID, "new Promise((resolve, reject) => { reject('foo'); resolve('bar'); })"); + assertEquals(2, rejectAfterResolve[0]); + assertEquals(2, resolveAfterResolve[0]); + } + +} From 4a3981ce985e527d84614980c18684da11eeff1b Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 10 Jul 2024 18:31:54 +0200 Subject: [PATCH 092/265] [GR-55244] PromiseRejectionTracker should not be shared between contexts. --- .../runtime/PromiseRejectionTrackerTest.java | 4 +- .../promise/CreateResolvingFunctionNode.java | 7 +- .../nodes/promise/PerformPromiseThenNode.java | 8 +- .../js/nodes/promise/RejectPromiseNode.java | 3 +- .../oracle/truffle/js/runtime/JSAgent.java | 47 +++++++++-- .../oracle/truffle/js/runtime/JSContext.java | 79 ++++++------------- .../oracle/truffle/js/runtime/JSRealm.java | 3 +- .../truffle/js/runtime/MainJSAgent.java | 6 +- .../truffle/js/runtime/util/DebugJSAgent.java | 5 +- .../truffle/trufflenode/GraalJSAccess.java | 4 +- 10 files changed, 86 insertions(+), 80 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/runtime/PromiseRejectionTrackerTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/runtime/PromiseRejectionTrackerTest.java index 2d3ccf3f210..18a8f3ff721 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/runtime/PromiseRejectionTrackerTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/runtime/PromiseRejectionTrackerTest.java @@ -50,6 +50,7 @@ import org.junit.Test; import com.oracle.truffle.js.lang.JavaScriptLanguage; +import com.oracle.truffle.js.runtime.JSAgent; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.PromiseRejectionTracker; import com.oracle.truffle.js.runtime.objects.JSDynamicObject; @@ -71,11 +72,12 @@ public void tearDown() { @Test public void testBasic() { JSContext context = JavaScriptLanguage.getJSContext(ctx); + JSAgent agent = JavaScriptLanguage.getJSRealm(ctx).getAgent(); final int[] rejected = new int[1]; final int[] handled = new int[1]; final int[] rejectAfterResolve = new int[1]; final int[] resolveAfterResolve = new int[1]; - context.setPromiseRejectionTracker(new PromiseRejectionTracker() { + context.setPromiseRejectionTracker(agent, new PromiseRejectionTracker() { @Override public void promiseRejected(JSDynamicObject promise, Object value) { rejected[0]++; diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/CreateResolvingFunctionNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/CreateResolvingFunctionNode.java index 6d3293ded26..645843fa0a3 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/CreateResolvingFunctionNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/CreateResolvingFunctionNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -55,6 +55,7 @@ import com.oracle.truffle.js.nodes.control.TryCatchNode; import com.oracle.truffle.js.nodes.unary.IsCallableNode; import com.oracle.truffle.js.runtime.Errors; +import com.oracle.truffle.js.runtime.JSAgent; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSFrameUtil; import com.oracle.truffle.js.runtime.JavaScriptRootNode; @@ -136,7 +137,7 @@ public Object execute(VirtualFrame frame) { Object resolution = resolutionNode.execute(frame); AlreadyResolved alreadyResolved = (AlreadyResolved) getAlreadyResolvedNode.getValue(functionObject); if (alreadyResolvedProfile.profile(alreadyResolved.value)) { - context.notifyPromiseRejectionTracker(promise, JSPromise.REJECTION_TRACKER_OPERATION_RESOLVE_AFTER_RESOLVED, resolution); + context.notifyPromiseRejectionTracker(promise, JSPromise.REJECTION_TRACKER_OPERATION_RESOLVE_AFTER_RESOLVED, resolution, JSAgent.get(this)); return Undefined.instance; } alreadyResolved.value = true; @@ -270,7 +271,7 @@ public Object execute(VirtualFrame frame) { Object reason = reasonNode.execute(frame); AlreadyResolved alreadyResolved = (AlreadyResolved) getAlreadyResolvedNode.getValue(functionObject); if (alreadyResolvedProfile.profile(alreadyResolved.value)) { - context.notifyPromiseRejectionTracker(promise, JSPromise.REJECTION_TRACKER_OPERATION_REJECT_AFTER_RESOLVED, reason); + context.notifyPromiseRejectionTracker(promise, JSPromise.REJECTION_TRACKER_OPERATION_REJECT_AFTER_RESOLVED, reason, JSAgent.get(this)); return Undefined.instance; } alreadyResolved.value = true; diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/PerformPromiseThenNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/PerformPromiseThenNode.java index 9717f742610..4a6d6510b7b 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/PerformPromiseThenNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/PerformPromiseThenNode.java @@ -48,6 +48,7 @@ import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.js.nodes.JavaScriptBaseNode; import com.oracle.truffle.js.nodes.unary.IsCallableNode; +import com.oracle.truffle.js.runtime.JSAgent; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRealm; import com.oracle.truffle.js.runtime.JobCallback; @@ -87,8 +88,9 @@ protected JSDynamicObject promiseThen(JSPromiseObject promise, Object onFulfille @Cached InlinedConditionProfile unhandledProf, @Cached InlinedBranchProfile growProfile) { JSRealm realm = getRealm(); - JobCallback onFulfilledHandler = isCallableFulfillNode.executeBoolean(onFulfilled) ? realm.getAgent().hostMakeJobCallback(onFulfilled) : null; - JobCallback onRejectedHandler = isCallableRejectNode.executeBoolean(onRejected) ? realm.getAgent().hostMakeJobCallback(onRejected) : null; + JSAgent agent = realm.getAgent(); + JobCallback onFulfilledHandler = isCallableFulfillNode.executeBoolean(onFulfilled) ? agent.hostMakeJobCallback(onFulfilled) : null; + JobCallback onRejectedHandler = isCallableRejectNode.executeBoolean(onRejected) ? agent.hostMakeJobCallback(onRejected) : null; assert resultCapability != null || (onFulfilledHandler != null && onRejectedHandler != null); PromiseReactionRecord fulfillReaction = PromiseReactionRecord.create(resultCapability, onFulfilledHandler, true); PromiseReactionRecord rejectReaction = PromiseReactionRecord.create(resultCapability, onRejectedHandler, false); @@ -107,7 +109,7 @@ protected JSDynamicObject promiseThen(JSPromiseObject promise, Object onFulfille Object reason = promise.getPromiseResult(); assert reason != null; if (unhandledProf.profile(this, !promise.isHandled())) { - context.notifyPromiseRejectionTracker(promise, JSPromise.REJECTION_TRACKER_OPERATION_HANDLE, Undefined.instance); + context.notifyPromiseRejectionTracker(promise, JSPromise.REJECTION_TRACKER_OPERATION_HANDLE, Undefined.instance, agent); } JSFunctionObject job = getPromiseReactionJob(rejectReaction, reason); context.enqueuePromiseJob(realm, job); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/RejectPromiseNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/RejectPromiseNode.java index f4b7605d9be..7363e47ef7e 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/RejectPromiseNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/RejectPromiseNode.java @@ -44,6 +44,7 @@ import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.js.nodes.JavaScriptBaseNode; import com.oracle.truffle.js.runtime.GraalJSException; +import com.oracle.truffle.js.runtime.JSAgent; import com.oracle.truffle.js.runtime.JSConfig; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.builtins.JSError; @@ -78,7 +79,7 @@ public Object execute(JSPromiseObject promise, Object reason) { promise.clearPromiseReactions(); JSPromise.setPromiseState(promise, JSPromise.REJECTED); if (unhandledProf.profile(!promise.isHandled())) { - context.notifyPromiseRejectionTracker(promise, JSPromise.REJECTION_TRACKER_OPERATION_REJECT, reason); + context.notifyPromiseRejectionTracker(promise, JSPromise.REJECTION_TRACKER_OPERATION_REJECT, reason, JSAgent.get(this)); } return triggerPromiseReactions.execute(reactions, reason); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSAgent.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSAgent.java index e2c666b447f..817eddf57b7 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSAgent.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSAgent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -51,12 +51,15 @@ import org.graalvm.collections.Equivalence; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.js.runtime.JSAgentWaiterList.JSAgentWaiterListEntry; import com.oracle.truffle.js.runtime.JSAgentWaiterList.WaiterRecord; import com.oracle.truffle.js.runtime.builtins.JSFinalizationRegistry; import com.oracle.truffle.js.runtime.builtins.JSFinalizationRegistryObject; import com.oracle.truffle.js.runtime.builtins.JSFunction; import com.oracle.truffle.js.runtime.builtins.JSFunctionObject; +import com.oracle.truffle.js.runtime.builtins.JSPromise; +import com.oracle.truffle.js.runtime.builtins.JSPromiseObject; import com.oracle.truffle.js.runtime.objects.AsyncContext; import com.oracle.truffle.js.runtime.objects.JSDynamicObject; import com.oracle.truffle.js.runtime.objects.Undefined; @@ -96,16 +99,11 @@ public abstract class JSAgent { private final Deque waitAsyncJobsQueue; - private final PromiseRejectionTracker promiseRejectionTracker; + private PromiseRejectionTracker promiseRejectionTracker; private AsyncContext asyncContextMapping = AsyncContext.empty(); public JSAgent(boolean canBlock) { - this(null, canBlock); - } - - public JSAgent(PromiseRejectionTracker promiseRejectionTracker, boolean canBlock) { - this.promiseRejectionTracker = promiseRejectionTracker; this.signifier = signifierGenerator.incrementAndGet(); this.canBlock = canBlock; this.promiseJobsQueue = new ArrayDeque<>(); @@ -271,6 +269,41 @@ public void setCanBlock(boolean canBlock) { */ public abstract void terminate(); + public static JSAgent get(Node node) { + return JSRealm.getMain(node).getAgent(); + } + + protected final boolean hasPromiseRejectionTracker() { + return promiseRejectionTracker != null; + } + + protected final void setPromiseRejectionTracker(PromiseRejectionTracker tracker) { + this.promiseRejectionTracker = tracker; + } + + @TruffleBoundary + protected final void notifyPromiseRejectionTracker(JSPromiseObject promise, int operation, Object value) { + if (!hasPromiseRejectionTracker()) { + return; + } + switch (operation) { + case JSPromise.REJECTION_TRACKER_OPERATION_REJECT: + promiseRejectionTracker.promiseRejected(promise, value); + break; + case JSPromise.REJECTION_TRACKER_OPERATION_HANDLE: + promiseRejectionTracker.promiseRejectionHandled(promise); + break; + case JSPromise.REJECTION_TRACKER_OPERATION_REJECT_AFTER_RESOLVED: + promiseRejectionTracker.promiseRejectedAfterResolved(promise, value); + break; + case JSPromise.REJECTION_TRACKER_OPERATION_RESOLVE_AFTER_RESOLVED: + promiseRejectionTracker.promiseResolvedAfterResolved(promise, value); + break; + default: + assert false : "Unknown operation: " + operation; + } + } + public AsyncContext getAsyncContextMapping() { return asyncContextMapping; } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContext.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContext.java index 5436844c05b..2fe0552dcfe 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContext.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContext.java @@ -110,6 +110,7 @@ import com.oracle.truffle.js.runtime.builtins.JSObjectFactory; import com.oracle.truffle.js.runtime.builtins.JSOrdinary; import com.oracle.truffle.js.runtime.builtins.JSPromise; +import com.oracle.truffle.js.runtime.builtins.JSPromiseObject; import com.oracle.truffle.js.runtime.builtins.JSProxy; import com.oracle.truffle.js.runtime.builtins.JSRawJSON; import com.oracle.truffle.js.runtime.builtins.JSRegExp; @@ -247,7 +248,6 @@ public class JSContext { private PrepareStackTraceCallback prepareStackTraceCallback; private final Assumption prepareStackTraceCallbackNotUsedAssumption; - private PromiseRejectionTracker promiseRejectionTracker; private final Assumption promiseRejectionTrackerNotUsedAssumption; private PromiseHook promiseHook; @@ -761,10 +761,6 @@ protected JSContext(Evaluator evaluator, JavaScriptLanguage lang, JSLanguageOpti this.regexValidateOptions = regexOptions.isEmpty() ? REGEX_OPTION_VALIDATE : REGEX_OPTION_VALIDATE + "," + regexOptions; this.supportedImportAttributes = languageOptions.importAttributes() ? Set.of(TYPE_IMPORT_ATTRIBUTE) : Set.of(); - - if (languageOptions.unhandledRejectionsMode() != JSContextOptions.UnhandledRejectionsTrackingMode.NONE) { - setPromiseRejectionTracker(new BuiltinPromiseRejectionTracker(this, languageOptions.unhandledRejectionsMode())); - } } public final Evaluator getEvaluator() { @@ -848,11 +844,7 @@ protected JSRealm createRealm(TruffleLanguage.Env env, JSRealm parentRealm) { newRealm.setupGlobals(); if (isTop) { - if (languageOptions.test262Mode() || languageOptions.testV8Mode()) { - newRealm.setAgent(new DebugJSAgent(getPromiseRejectionTracker(), languageOptions.agentCanBlock())); - } else { - newRealm.setAgent(new MainJSAgent(getPromiseRejectionTracker())); - } + newRealm.setAgent(createAgent()); if (languageOptions.v8RealmBuiltin()) { newRealm.initRealmList(); newRealm.addToRealmList(newRealm); @@ -871,6 +863,19 @@ protected JSRealm createRealm(TruffleLanguage.Env env, JSRealm parentRealm) { return newRealm; } + private JSAgent createAgent() { + JSAgent agent; + if (languageOptions.test262Mode() || languageOptions.testV8Mode()) { + agent = new DebugJSAgent(languageOptions.agentCanBlock()); + } else { + agent = new MainJSAgent(); + } + if (languageOptions.unhandledRejectionsMode() != JSContextOptions.UnhandledRejectionsTrackingMode.NONE) { + setPromiseRejectionTracker(agent, new BuiltinPromiseRejectionTracker(this, languageOptions.unhandledRejectionsMode())); + } + return agent; + } + public final Shape createEmptyShape() { return makeEmptyShapeWithNullPrototype(JSOrdinary.INSTANCE); } @@ -1611,13 +1616,9 @@ private void invalidatePrepareStackTraceCallbackNotUsedAssumption() { } } - public PromiseRejectionTracker getPromiseRejectionTracker() { - return promiseRejectionTracker; - } - - public final void setPromiseRejectionTracker(PromiseRejectionTracker tracker) { + public final void setPromiseRejectionTracker(JSAgent agent, PromiseRejectionTracker tracker) { invalidatePromiseRejectionTrackerNotUsedAssumption(); - this.promiseRejectionTracker = tracker; + agent.setPromiseRejectionTracker(tracker); } private void invalidatePromiseRejectionTrackerNotUsedAssumption() { @@ -1627,45 +1628,13 @@ private void invalidatePromiseRejectionTrackerNotUsedAssumption() { } } - public void notifyPromiseRejectionTracker(JSDynamicObject promise, int operation, Object value) { - if (!promiseRejectionTrackerNotUsedAssumption.isValid() && promiseRejectionTracker != null) { - switch (operation) { - case JSPromise.REJECTION_TRACKER_OPERATION_REJECT: - invokePromiseRejected(promise, value); - break; - case JSPromise.REJECTION_TRACKER_OPERATION_HANDLE: - invokePromiseRejectionHandled(promise); - break; - case JSPromise.REJECTION_TRACKER_OPERATION_REJECT_AFTER_RESOLVED: - invokePromiseRejectedAfterResolved(promise, value); - break; - case JSPromise.REJECTION_TRACKER_OPERATION_RESOLVE_AFTER_RESOLVED: - invokePromiseResolvedAfterResolved(promise, value); - break; - default: - assert false : "Unknown operation: " + operation; - } + public void notifyPromiseRejectionTracker(JSPromiseObject promise, int operation, Object value, JSAgent agent) { + boolean hasPromiseRejectionTracker = agent.hasPromiseRejectionTracker(); + if (promiseRejectionTrackerNotUsedAssumption.isValid()) { + assert !hasPromiseRejectionTracker : promiseRejectionTrackerNotUsedAssumption; + return; } - } - - @TruffleBoundary - private void invokePromiseRejected(JSDynamicObject promise, Object value) { - promiseRejectionTracker.promiseRejected(promise, value); - } - - @TruffleBoundary - private void invokePromiseRejectionHandled(JSDynamicObject promise) { - promiseRejectionTracker.promiseRejectionHandled(promise); - } - - @TruffleBoundary - private void invokePromiseRejectedAfterResolved(JSDynamicObject promise, Object value) { - promiseRejectionTracker.promiseRejectedAfterResolved(promise, value); - } - - @TruffleBoundary - private void invokePromiseResolvedAfterResolved(JSDynamicObject promise, Object value) { - promiseRejectionTracker.promiseResolvedAfterResolved(promise, value); + agent.notifyPromiseRejectionTracker(promise, operation, value); } public final void setPromiseHook(PromiseHook promiseHook) { @@ -1696,7 +1665,7 @@ public final void notifyPromiseHook(int changeType, JSDynamicObject promise) { notifyPromiseHookImpl(changeType, promise, parent); } catch (GraalJSException ex) { // Resembles ReportMessageFromMicrotask() - notifyPromiseRejectionTracker(JSPromise.create(this, getRealm()), JSPromise.REJECTION_TRACKER_OPERATION_REJECT, ex.getErrorObject()); + notifyPromiseRejectionTracker(JSPromise.create(this, getRealm()), JSPromise.REJECTION_TRACKER_OPERATION_REJECT, ex.getErrorObject(), realm.getAgent()); } } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java index df9c651fd1c..f59aae0d7ed 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java @@ -3000,9 +3000,8 @@ public final JSAgent getAgent() { } public void setAgent(JSAgent newAgent) { - assert newAgent != null : "Cannot set a null agent!"; CompilerAsserts.neverPartOfCompilation("Assigning agent to context in compiled code"); - this.agent = newAgent; + this.agent = Objects.requireNonNull(newAgent, "agent"); } public TimeZone getLocalTimeZone() { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/MainJSAgent.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/MainJSAgent.java index d3fea41fc5e..bcaab8cfe72 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/MainJSAgent.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/MainJSAgent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -45,8 +45,8 @@ */ public final class MainJSAgent extends JSAgent { - public MainJSAgent(PromiseRejectionTracker promiseRejectionTracker) { - super(promiseRejectionTracker, false); + public MainJSAgent() { + super(false); } @Override diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/DebugJSAgent.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/DebugJSAgent.java index 9ebad49731f..b7105a0cfdb 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/DebugJSAgent.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/DebugJSAgent.java @@ -63,7 +63,6 @@ import com.oracle.truffle.js.runtime.JSAgent; import com.oracle.truffle.js.runtime.JSInterruptedExecutionException; import com.oracle.truffle.js.runtime.JSRealm; -import com.oracle.truffle.js.runtime.PromiseRejectionTracker; import com.oracle.truffle.js.runtime.builtins.JSFunction; import com.oracle.truffle.js.runtime.builtins.JSFunctionObject; import com.oracle.truffle.js.runtime.objects.Null; @@ -84,8 +83,8 @@ public class DebugJSAgent extends JSAgent { static final int POLL_TIMEOUT_MS = 100; - public DebugJSAgent(PromiseRejectionTracker promiseRejectionTracker, boolean canBlock) { - super(promiseRejectionTracker, canBlock); + public DebugJSAgent(boolean canBlock) { + super(canBlock); this.reportValues = new ConcurrentLinkedDeque<>(); this.spawnedAgents = new LinkedList<>(); this.queueLock = new ReentrantLock(); diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java index 22c43c07388..746fd2c5feb 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java @@ -3000,7 +3000,7 @@ public void isolateRunMicrotasks() { } else { errorObject = atex; } - mainJSContext.notifyPromiseRejectionTracker(JSPromise.create(mainJSContext, getCurrentRealm()), JSPromise.REJECTION_TRACKER_OPERATION_REJECT, errorObject); + mainJSContext.notifyPromiseRejectionTracker(JSPromise.create(mainJSContext, getCurrentRealm()), JSPromise.REJECTION_TRACKER_OPERATION_REJECT, errorObject, agent); } } catch (Exception ex) { ex.printStackTrace(); @@ -3235,7 +3235,7 @@ public void isolateEnablePromiseHook(boolean enable) { public void isolateEnablePromiseRejectCallback(boolean enable) { PromiseRejectionTracker tracker = enable ? new NativePromiseRejectionTracker() : null; - mainJSContext.setPromiseRejectionTracker(tracker); + mainJSContext.setPromiseRejectionTracker(agent, tracker); } public void isolateEnableImportMetaInitializer(boolean enable) { From 52cd1975e9c0f8b0b646ebf47e39e7e54da5d061 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 11 Jul 2024 01:06:59 +0200 Subject: [PATCH 093/265] [GR-55244] Add regression test. Unhandled promise rejection errors must not leak from one context to another. --- .../truffle/js/test/regress/GR55244.java | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR55244.java diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR55244.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR55244.java new file mode 100644 index 00000000000..47d47c00e3b --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR55244.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.test.regress; + +import static com.oracle.truffle.js.runtime.JSContextOptions.UNHANDLED_REJECTIONS_NAME; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +import java.util.Map; + +import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.Engine; +import org.graalvm.polyglot.PolyglotException; +import org.graalvm.polyglot.Value; +import org.graalvm.polyglot.proxy.ProxyExecutable; +import org.graalvm.polyglot.proxy.ProxyObject; +import org.junit.Test; + +import com.oracle.truffle.js.test.JSTest; + +public class GR55244 { + + /** + * Unhandled promise rejection errors must not leak from one context to another. + */ + @Test + public void testPromiseRejectionTracker() { + Object converters = ProxyObject.fromMap(Map.of( + "fromInt32ToNumber", (ProxyExecutable) (a) -> a[0].asInt(), + "toInt32", (ProxyExecutable) (a) -> a[0].asInt())); + + try (Engine eng = JSTest.newEngineBuilder().build()) { + try (Context c1 = JSTest.newContextBuilder().engine(eng).option(UNHANDLED_REJECTIONS_NAME, "throw").build()) { + c1.getBindings("js").putMember("converters", converters); + Value func = c1.eval("js", """ + (async function(args, result_setter) { + let x = converters.fromInt32ToNumber(args.x); + async function async_error_handling4() { + async function foo() { + throw "Error from foo()"; + } + let y = foo(); // here it does not throw, only the Promise is created + + throw "Error from entry-point func"; + return 42; + } + result_setter(converters.toInt32(await async_error_handling4())); + }) + """); + try { + func.execute(ProxyObject.fromMap(Map.of("x", 41)), (ProxyExecutable) (a) -> { + assertEquals(1, a.length); + assertEquals(42, a[0].asInt()); + return null; + }); + fail("should have thrown"); + } catch (PolyglotException e) { + assertThat(e.getMessage(), containsString("Unhandled promise rejection: Error from foo()")); + } + } + + try (Context c2 = JSTest.newContextBuilder().engine(eng).option(UNHANDLED_REJECTIONS_NAME, "throw").build()) { + c2.getBindings("js").putMember("converters", converters); + Value func = c2.eval("js", """ + (async function(args, result_setter) { + let x = converters.fromInt32ToNumber(args.x); + async function foo() { return x + 1; } + result_setter(converters.toInt32(await foo())); + }) + """); + func.execute(ProxyObject.fromMap(Map.of("x", 41)), (ProxyExecutable) (a) -> { + assertEquals(1, a.length); + assertEquals(42, a[0].asInt()); + return null; + }); + } + } + } +} From f0541451e51e9692c5f77f3addad592a7b641e8a Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 12 Jul 2024 21:04:28 +0000 Subject: [PATCH 094/265] Update graal import. --- graal-js/mx.graal-js/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/mx.graal-js/suite.py b/graal-js/mx.graal-js/suite.py index 00a9e7cd8ee..917b73d6510 100644 --- a/graal-js/mx.graal-js/suite.py +++ b/graal-js/mx.graal-js/suite.py @@ -24,7 +24,7 @@ { "name" : "regex", "subdir" : True, - "version" : "9d02a101054894edf80d1dfc1fc1960ae3aef772", + "version" : "1b5b284ffb425c5479be7c36d8813996249945b8", "urls" : [ {"url" : "https://github.com/oracle/graal.git", "kind" : "git"}, ] From 14c89512e798e959c9239c67e9e2010ad254e3f9 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Sun, 14 Jul 2024 17:55:22 +0200 Subject: [PATCH 095/265] Fixing Windows build: adding v8::TryHandleWebAssemblyTrapWindows(). --- graal-nodejs/deps/v8/src/graal/v8.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/graal-nodejs/deps/v8/src/graal/v8.cc b/graal-nodejs/deps/v8/src/graal/v8.cc index 145f30a2b20..43404ab858c 100644 --- a/graal-nodejs/deps/v8/src/graal/v8.cc +++ b/graal-nodejs/deps/v8/src/graal/v8.cc @@ -82,6 +82,9 @@ #ifdef __POSIX__ #include "v8-wasm-trap-handler-posix.h" #endif +#if defined(_WIN32) +#include "v8-wasm-trap-handler-win.h" +#endif #include "libplatform/libplatform.h" #include "libplatform/v8-tracing.h" #include "src/base/once.h" @@ -3754,6 +3757,13 @@ namespace v8 { } #endif +#if defined(_WIN32) + bool TryHandleWebAssemblyTrapWindows(EXCEPTION_POINTERS* exception) { + TRACE + return false; + } +#endif + CpuProfilingOptions::CpuProfilingOptions(CpuProfilingMode mode, unsigned max_samples, int sampling_interval_us, MaybeLocal filter_context) { TRACE } From f906aeae8e467d6c35e19696a89c2daf2dcf4215 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Sun, 14 Jul 2024 18:39:35 +0200 Subject: [PATCH 096/265] Do not attempt to get a namespace object for an unlinked module. --- .../src/com/oracle/truffle/trufflenode/GraalJSAccess.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java index 22c43c07388..0070581b70e 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java @@ -2726,6 +2726,11 @@ private WeakCallback updateWeakCallback(Object object, long reference, long data target = jsObject; key = HIDDEN_WEAK_CALLBACK; } else if (object instanceof JSModuleRecord moduleRecord) { + if (moduleRecord.getStatus() == JSModuleRecord.Status.Unlinked) { + assert (callbackPointer == 0); + // ClearWeak() called on a module that cannot be weak yet + return null; + } target = moduleRecord.getContext().getEvaluator().getModuleNamespace(moduleRecord); key = HIDDEN_WEAK_CALLBACK_SUBSTITUTE; } else { @@ -4255,6 +4260,7 @@ public JSModuleRecord resolveImportedModule(ScriptOrModule referrer, ModuleReque } } if (resolver == 0) { + Thread.dumpStack(); System.err.println("Cannot resolve module outside module instantiation!"); System.exit(1); } From 178ac555528492ee97ebe9b07a8ada6eec910c65 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Sun, 14 Jul 2024 18:41:22 +0200 Subject: [PATCH 097/265] Updating Node.js version in 3rd_party_licenses.txt. --- 3rd_party_licenses.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3rd_party_licenses.txt b/3rd_party_licenses.txt index 09f403c3e6b..1a994b44ae3 100644 --- a/3rd_party_licenses.txt +++ b/3rd_party_licenses.txt @@ -512,7 +512,7 @@ THE POSSIBILITY OF SUCH DAMAGE. ================================================================================ -Node.js 20.13.1 +Node.js 20.15.1 Node.js is licensed for use as follows: From 7752d3eac671a42c9a74831ffb83cfa7f857612f Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 15 Jul 2024 14:34:04 +0200 Subject: [PATCH 098/265] Aggregate multiple unhandled promise rejection errors into one error. --- .../truffle/js/test/regress/GR55244.java | 39 ++++++++++++++++++- .../BuiltinPromiseRejectionTracker.java | 22 ++++++++++- .../com/oracle/truffle/js/runtime/Errors.java | 12 +++++- 3 files changed, 68 insertions(+), 5 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR55244.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR55244.java index 47d47c00e3b..0cf43a7c5c0 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR55244.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/regress/GR55244.java @@ -44,6 +44,8 @@ import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.Map; @@ -95,7 +97,18 @@ async function foo() { }); fail("should have thrown"); } catch (PolyglotException e) { - assertThat(e.getMessage(), containsString("Unhandled promise rejection: Error from foo()")); + assertThat(e.getMessage(), containsString("AggregateError: Unhandled promise rejections")); + Value errors = e.getGuestObject().getMember("errors"); + assertNotNull("errors", errors); + assertTrue(errors.hasArrayElements()); + assertEquals(2, errors.getArraySize()); + assertTrue(errors.getArrayElement(0).isException()); + assertTrue(errors.getArrayElement(1).isException()); + try { + errors.getArrayElement(0).throwException(); + } catch (PolyglotException e0) { + assertThat(e0.getMessage(), containsString("Error from foo()")); + } } } @@ -116,4 +129,28 @@ async function foo() { } } } + + /** + * Aggregate multiple unhandled promise rejection errors into one error. + */ + @Test + public void testMultipleRejections() { + try (Engine eng = JSTest.newEngineBuilder().build()) { + try (Context ctx = JSTest.newContextBuilder().engine(eng).option(UNHANDLED_REJECTIONS_NAME, "throw").build()) { + try { + ctx.eval("js", "Promise.reject(42); Promise.reject(211);"); + fail("should have thrown"); + } catch (PolyglotException e) { + assertThat(e.getMessage(), containsString("AggregateError: Unhandled promise rejections")); + Value errors = e.getGuestObject().getMember("errors"); + assertNotNull("errors", errors); + assertTrue(errors.hasArrayElements()); + assertEquals(2, errors.getArraySize()); + assertTrue(errors.getArrayElement(0).isException()); + assertTrue(errors.getArrayElement(1).isException()); + } + ctx.eval("js", "1 + 1"); + } + } + } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/BuiltinPromiseRejectionTracker.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/BuiltinPromiseRejectionTracker.java index d65b4c21278..125115c1b71 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/BuiltinPromiseRejectionTracker.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/BuiltinPromiseRejectionTracker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,22 +41,27 @@ package com.oracle.truffle.js.nodes.promise; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.Deque; import java.util.LinkedHashSet; import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.WeakHashMap; import com.oracle.truffle.api.CompilerAsserts; +import com.oracle.truffle.api.exception.AbstractTruffleException; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.js.runtime.Errors; +import com.oracle.truffle.js.runtime.GraalJSException; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSContextOptions; import com.oracle.truffle.js.runtime.JSRealm; import com.oracle.truffle.js.runtime.JSRuntime; import com.oracle.truffle.js.runtime.PromiseRejectionTracker; +import com.oracle.truffle.js.runtime.builtins.JSArray; import com.oracle.truffle.js.runtime.interop.JSInteropUtil; import com.oracle.truffle.js.runtime.objects.JSDynamicObject; import com.oracle.truffle.js.runtime.objects.Undefined; @@ -120,6 +125,7 @@ public void promiseReactionJobsProcessed() { } } + List errors = new ArrayList<>(); // Take one at a time as the rejection handler could queue up more rejections. while (!pendingUnhandledRejections.isEmpty()) { JSDynamicObject unhandledPromise = pendingUnhandledRejections.iterator().next(); @@ -147,9 +153,21 @@ public void promiseReactionJobsProcessed() { try { interop.throwException(info.reason); } catch (UnsupportedMessageException e) { + } catch (AbstractTruffleException e) { + errors.add(e); + continue; } } - throw Errors.createError("Unhandled promise rejection: " + formatError(info.reason)); + errors.add(Errors.createError("Unhandled promise rejection: " + formatError(info.reason))); + } + } + if (mode == JSContextOptions.UnhandledRejectionsTrackingMode.THROW && !errors.isEmpty()) { + if (errors.size() == 1) { + throw errors.get(0); + } else { + throw Errors.createAggregateError(JSArray.createConstant(context, realm, errors.stream().map(e -> { + return e instanceof GraalJSException ex ? ex.getErrorObject() : e; + }).toArray()), "Unhandled promise rejections", null); } } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Errors.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Errors.java index c1c952274a0..10738019520 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Errors.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Errors.java @@ -69,16 +69,24 @@ private Errors() { } @TruffleBoundary - public static JSException createAggregateError(Object errors, Node originatingNode) { + public static JSException createAggregateError(Object errors, String message, Node originatingNode) { JSContext context = JavaScriptLanguage.get(originatingNode).getJSContext(); JSRealm realm = JSRealm.get(originatingNode); JSErrorObject errorObj = JSError.createErrorObject(context, realm, JSErrorType.AggregateError); + if (message != null) { + JSError.setMessage(errorObj, Strings.fromJavaString(message)); + } JSObjectUtil.putDataProperty(errorObj, JSError.ERRORS_NAME, errors, JSError.ERRORS_ATTRIBUTES); - JSException exception = JSException.create(JSErrorType.AggregateError, null, errorObj, realm); + JSException exception = JSException.create(JSErrorType.AggregateError, message, errorObj, realm); JSError.setException(realm, errorObj, exception, false); return exception; } + @TruffleBoundary + public static JSException createAggregateError(Object errors, Node originatingNode) { + return createAggregateError(errors, null, originatingNode); + } + @TruffleBoundary public static JSException createError(String message) { return JSException.create(JSErrorType.Error, message); From f22473de8761e91df1805d8d75a3a8724b8c9588 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Mon, 15 Jul 2024 21:49:08 +0200 Subject: [PATCH 099/265] Ensure that there is a scope when parsing a formal parameter list. --- .../src/com/oracle/js/parser/Parser.java | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java index 9ec09a3d8d4..6034e857e26 100644 --- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java +++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java @@ -615,7 +615,26 @@ public void parseFormalParameterList() { scanFirstToken(); assert lc.getCurrentScope() == null; - formalParameterList(TokenType.EOF, false, false); + + // Set up a fake function. + final int functionLine = line; + final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength()); + final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), lexer.stringIntern(PROGRAM_NAME)); + final ParserContextFunctionNode function = createParserContextFunctionNode(ident, functionToken, 0, functionLine); + function.clearFlag(FunctionNode.IS_PROGRAM); + + lc.push(function); + try { + final ParserContextBlockNode parameterBlock = function.createParameterBlock(); + lc.push(parameterBlock); + try { + formalParameterList(TokenType.EOF, false, false); + } finally { + restoreBlock(parameterBlock); + } + } finally { + lc.pop(function); + } } catch (ParserException e) { handleParseException(e); } @@ -2681,9 +2700,7 @@ private IdentNode bindingIdentifier(boolean yield, boolean await, String context private void addIdentifierReference(String name) { Scope currentScope = lc.getCurrentScope(); - if (currentScope != null) { // can be null when parsing/verifying a parameter list. - currentScope.addIdentifierReference(name); - } + currentScope.addIdentifierReference(name); } private Expression bindingPattern(boolean yield, boolean await) { From 2a5f2d956b3f67cc0c4c5311fb5360fdf9b3389c Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Mon, 15 Jul 2024 22:00:28 +0200 Subject: [PATCH 100/265] Regression test for the parsing of some special formal parameter lists. --- .../com.oracle.truffle.js.test/js/GR-55493.js | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 graal-js/src/com.oracle.truffle.js.test/js/GR-55493.js diff --git a/graal-js/src/com.oracle.truffle.js.test/js/GR-55493.js b/graal-js/src/com.oracle.truffle.js.test/js/GR-55493.js new file mode 100644 index 00000000000..a61ec32ed21 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/js/GR-55493.js @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ + +/** + * Ensure that the parsing of some special parameter lists does not result in + * an internal error. + */ + +load("assert.js"); + +var fn; + +fn = new Function("{ arguments }", "return arguments"); +assertSame('foo', fn({ arguments: 'foo' })); + +fn = new Function("x = eval(6*7)", "return x"); +assertSame(42, fn()); + +assertThrows(() => eval('new Function("x = this.#y", "")'), SyntaxError); + +assertThrows(() => eval('new Function("x = super.y", "")'), SyntaxError); From 6692fa8f9b80e17b299b6a83d0bfc9d58f420e1e Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Fri, 14 Jun 2024 00:48:29 +0200 Subject: [PATCH 101/265] Do not set engine.AssertProbes=true when assertions are disabled. --- graal-js/mx.graal-js/mx_graal_js.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/graal-js/mx.graal-js/mx_graal_js.py b/graal-js/mx.graal-js/mx_graal_js.py index 906cbc7db60..1d70205ff7f 100644 --- a/graal-js/mx.graal-js/mx_graal_js.py +++ b/graal-js/mx.graal-js/mx_graal_js.py @@ -159,9 +159,11 @@ def processDeps(self, deps): def apply(self, config): (vmArgs, mainClass, mainClassArgs) = config # Disable DefaultRuntime warning - vmArgs = vmArgs + ['-Dpolyglot.engine.WarnInterpreterOnly=false'] - # Assert for enter/return parity of ProbeNode - vmArgs = vmArgs + ['-Dpolyglot.engine.AssertProbes=true', '-Dpolyglot.engine.AllowExperimentalOptions=true'] + vmArgs += ['-Dpolyglot.engine.WarnInterpreterOnly=false'] + vmArgs += ['-Dpolyglot.engine.AllowExperimentalOptions=true'] + # Assert for enter/return parity of ProbeNode (if assertions are enabled only) + if next((arg.startswith('-e') for arg in reversed(vmArgs) if arg in ['-ea', '-da', '-enableassertions', '-disableassertions']), False): + vmArgs += ['-Dpolyglot.engine.AssertProbes=true'] vmArgs += ['-Dpolyglotimpl.DisableClassPathIsolation=true'] mainClassArgs += ['-JUnitOpenPackages', 'org.graalvm.js/*=com.oracle.truffle.js.test'] mainClassArgs += ['-JUnitOpenPackages', 'org.graalvm.js/*=com.oracle.truffle.js.snapshot'] From 23bfc0d568dd9961a9b1e999b2b2c78e5b6332f1 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Sun, 14 Jul 2024 13:34:50 +0200 Subject: [PATCH 102/265] Adding an option that enables/disables stack-trace-related extensions. --- .../js/nodes/access/ErrorStackTraceLimitNode.java | 2 +- .../oracle/truffle/js/runtime/JSContextOptions.java | 10 ++++++++++ .../src/com/oracle/truffle/js/runtime/JSException.java | 2 +- .../oracle/truffle/js/runtime/JSLanguageOptions.java | 3 +++ .../src/com/oracle/truffle/js/runtime/JSRealm.java | 8 -------- .../oracle/truffle/js/runtime/builtins/JSError.java | 6 ++++-- 6 files changed, 19 insertions(+), 12 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ErrorStackTraceLimitNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ErrorStackTraceLimitNode.java index 2ba0a2f6c25..59dd65329fa 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ErrorStackTraceLimitNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ErrorStackTraceLimitNode.java @@ -70,7 +70,7 @@ protected final int doInt( @Cached IsNumberNode isNumber, @Cached JSToIntegerAsLongNode toInteger) { JSContext context = getJSContext(); - if (context.isOptionV8CompatibilityMode() || context.getLanguageOptions().isMLEMode()) { + if (context.getLanguageOptions().stackTraceAPI()) { JSFunctionObject errorConstructor = getRealm().getErrorConstructor(JSErrorType.Error); if (JSProperty.isData(getStackTraceLimit.getPropertyFlagsOrDefault(errorConstructor, JSError.STACK_TRACE_LIMIT_PROPERTY_NAME, JSProperty.ACCESSOR))) { Object value = getStackTraceLimit.getOrDefault(errorConstructor, JSError.STACK_TRACE_LIMIT_PROPERTY_NAME, Undefined.instance); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java index eff031cf1b7..d73285c5144 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java @@ -594,6 +594,11 @@ public Map apply(String value) { public static final OptionKey ARRAY_ELEMENTS_AMONG_MEMBERS = new OptionKey<>(true); @CompilationFinal private boolean arrayElementsAmongMembers; + public static final String STACK_TRACE_API_NAME = JS_OPTION_PREFIX + "stack-trace-api"; + @Option(name = STACK_TRACE_API_NAME, category = OptionCategory.EXPERT, help = "Enable Stack Trace API (Error.captureStackTrace/prepareStackTrace/stackTraceLimit).") // + public static final OptionKey STACK_TRACE_API = new OptionKey<>(true); + @CompilationFinal private boolean stackTraceAPI; + public enum UnhandledRejectionsTrackingMode { NONE, WARN, @@ -798,6 +803,7 @@ private void cacheOptions(SandboxPolicy sandboxPolicy) { this.allowNarrowSpacesInDateFormat = ALLOW_NARROW_SPACES_IN_DATE_FORMAT.hasBeenSet(optionValues) ? readBooleanOption(ALLOW_NARROW_SPACES_IN_DATE_FORMAT) : !isV8CompatibilityMode(); this.v8Intrinsics = readBooleanOption(V8_INTRINSICS); this.arrayElementsAmongMembers = readBooleanOption(ARRAY_ELEMENTS_AMONG_MEMBERS); + this.stackTraceAPI = readBooleanOption(STACK_TRACE_API); } private UnhandledRejectionsTrackingMode readUnhandledRejectionsMode() { @@ -1267,6 +1273,10 @@ public boolean isArrayElementsAmongMembers() { return arrayElementsAmongMembers; } + public boolean isStackTraceAPI() { + return stackTraceAPI; + } + public short getFrequencyBasedPropertyCacheLimit() { return frequencyBasedPropertyCacheLimit; } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSException.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSException.java index 44b77ac4a52..d5cb728591c 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSException.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSException.java @@ -151,7 +151,7 @@ public static JSException create(JSErrorType type, String message, Throwable cau public static int getStackTraceLimit(JSRealm realm) { JSContextOptions contextOptions = realm.getContextOptions(); - if (contextOptions.isV8CompatibilityMode() || contextOptions.isMLEMode()) { + if (contextOptions.isStackTraceAPI()) { JSFunctionObject errorConstructor = realm.getErrorConstructor(JSErrorType.Error); DynamicObjectLibrary lib = DynamicObjectLibrary.getUncached(); if (JSProperty.isData(lib.getPropertyFlagsOrDefault(errorConstructor, JSError.STACK_TRACE_LIMIT_PROPERTY_NAME, JSProperty.ACCESSOR))) { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSLanguageOptions.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSLanguageOptions.java index 6f69a5e5d17..dedec1c1799 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSLanguageOptions.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSLanguageOptions.java @@ -128,6 +128,7 @@ public record JSLanguageOptions( boolean constAsVar, boolean profileTime, boolean arrayElementsAmongMembers, + boolean stackTraceAPI, String locale) { public static JSLanguageOptions fromOptionValues(SandboxPolicy sandboxPolicy, OptionValues optionValues) { @@ -209,6 +210,7 @@ public static JSLanguageOptions fromContextOptions(JSContextOptions options) { boolean constAsVar = options.isConstAsVar(); boolean profileTime = options.isProfileTime(); boolean arrayElementsAmongMembers = options.isArrayElementsAmongMembers(); + boolean stackTraceAPI = options.isStackTraceAPI(); String locale = options.getLocale(); return new JSLanguageOptions( @@ -285,6 +287,7 @@ public static JSLanguageOptions fromContextOptions(JSContextOptions options) { constAsVar, profileTime, arrayElementsAmongMembers, + stackTraceAPI, locale); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java index c2e1cff5b3e..d16ab76b719 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java @@ -2246,7 +2246,6 @@ public void addOptionalGlobals() { setupJavaInterop(); } addCommonJSGlobals(); - addErrorStackTraceLimit(); } private void addGlobalGlobal() { @@ -2255,13 +2254,6 @@ private void addGlobalGlobal() { } } - private void addErrorStackTraceLimit() { - if (getContextOptions().isV8CompatibilityMode() || getContextOptions().isMLEMode()) { - JSObject errorConstructor = getErrorConstructor(JSErrorType.Error); - JSObjectUtil.putDataProperty(errorConstructor, JSError.STACK_TRACE_LIMIT_PROPERTY_NAME, getContextOptions().getStackTraceLimit(), JSAttributes.getDefault()); - } - } - private void addShellGlobals() { if (getContextOptions().isShell()) { GlobalBuiltins.GLOBAL_SHELL.forEachBuiltin((Builtin builtin) -> { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSError.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSError.java index 9deb1a8676d..5c0c09154ab 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSError.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSError.java @@ -54,6 +54,7 @@ import com.oracle.truffle.js.runtime.GraalJSException; import com.oracle.truffle.js.runtime.GraalJSException.JSStackTraceElement; import com.oracle.truffle.js.runtime.JSContext; +import com.oracle.truffle.js.runtime.JSContextOptions; import com.oracle.truffle.js.runtime.JSErrorType; import com.oracle.truffle.js.runtime.JSException; import com.oracle.truffle.js.runtime.JSRealm; @@ -209,8 +210,9 @@ public static JSConstructor createErrorConstructor(JSRealm realm, JSErrorType er JSObjectUtil.putConstructorProperty(classPrototype, errorConstructor); JSObjectUtil.putDataProperty(classPrototype, NAME, name, MESSAGE_ATTRIBUTES); JSObjectUtil.putConstructorPrototypeProperty(errorConstructor, classPrototype); - if (errorType == JSErrorType.Error) { + if (realm.getContextOptions().isStackTraceAPI() && errorType == JSErrorType.Error) { JSObjectUtil.putFunctionsFromContainer(realm, errorConstructor, ErrorFunctionBuiltins.BUILTINS); + JSObjectUtil.putDataProperty(errorConstructor, STACK_TRACE_LIMIT_PROPERTY_NAME, JSContextOptions.STACK_TRACE_LIMIT.getValue(realm.getOptions()), JSAttributes.getDefault()); } return new JSConstructor(errorConstructor, classPrototype); @@ -313,7 +315,7 @@ public static Object prepareStack(JSRealm realm, JSDynamicObject errorObj, Graal */ @TruffleBoundary public static Object prepareStackNoCallback(JSRealm realm, JSDynamicObject errorObj, JSStackTraceElement[] jsStackTrace) { - if (realm.getContextOptions().isV8CompatibilityMode()) { + if (realm.getContextOptions().isStackTraceAPI()) { JSFunctionObject error = realm.getErrorConstructor(JSErrorType.Error); Object prepareStackTrace = JSObject.get(error, PREPARE_STACK_TRACE_NAME); if (JSFunction.isJSFunction(prepareStackTrace)) { From 6eecdcec08e2b9bf17a13fb96c3eabe4618b2aa0 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Sun, 14 Jul 2024 13:35:27 +0200 Subject: [PATCH 103/265] Testing js.stack-trace-api option. --- graal-js/src/com.oracle.truffle.js.test/js/GR-54930.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/graal-js/src/com.oracle.truffle.js.test/js/GR-54930.js b/graal-js/src/com.oracle.truffle.js.test/js/GR-54930.js index 10e61d0d3a7..647e02949f5 100644 --- a/graal-js/src/com.oracle.truffle.js.test/js/GR-54930.js +++ b/graal-js/src/com.oracle.truffle.js.test/js/GR-54930.js @@ -5,12 +5,21 @@ * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. */ +/** + * Sanity check of stack-trace-api option. + * + * @option stack-trace-api=false + */ + load("assert.js"); function createError(n) { return n ? createError(n-1) : new Error(); } +// Error.captureStackTrace should not be defined +assertSame(undefined, Error.captureStackTrace); + // Error.stackTraceLimit should have no impact on the stack property var expected = createError(10).stack; From 97fe76846de615636ba095aae02b3b383778af8b Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Sun, 14 Jul 2024 13:36:28 +0200 Subject: [PATCH 104/265] Adding a note about js.stack-trace-api option into change-log. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfdbf3516a3..18a844a2b1c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,7 @@ See [release calendar](https://www.graalvm.org/release-calendar/) for release da ## Version 24.2.0 * Implemented the [`Promise.try`](https://github.com/tc39/proposal-promise-try) proposal. It is available in ECMAScript staging mode (`--js.ecmascript-version=staging`). -* Usage of non-standard extensions `Error.prepareStackTrace` and `Error.stackTraceLimit` has been limited to `js.v8-compat` mode only. +* Added option `js.stack-trace-api` that enables/disables `Error.captureStackTrace`, `Error.prepareStackTrace` and `Error.stackTraceLimit`. ## Version 24.1.0 * ECMAScript 2024 mode/features enabled by default. From 3abf9cfa314fdce1246cbda9645e1750bc92b19c Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Tue, 16 Jul 2024 23:31:45 +0200 Subject: [PATCH 105/265] Disabling mjsunit/random-bit-correlations.js test. --- graal-js/test/testV8.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/graal-js/test/testV8.json b/graal-js/test/testV8.json index 8e8859e2a9a..956eed4c6e4 100644 --- a/graal-js/test/testV8.json +++ b/graal-js/test/testV8.json @@ -938,6 +938,10 @@ "filePath" : "mjsunit/rab-gsab-transfer-to-worker.js", "status" : "FAIL", "comment" : "Uses Worker" + }, { + "filePath" : "mjsunit/random-bit-correlations.js", + "status" : "SKIP", + "comment" : "Statistical check of the quality of the random number generator. It is unstable unless a fixed seed is used." }, { "filePath" : "mjsunit/realm-property-access.js", "status" : "FAIL" From af6b4a449d548e524967a86f6752414f122518e6 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Tue, 16 Jul 2024 23:51:37 +0200 Subject: [PATCH 106/265] Disabling unstable Atomics/waitAsync/**/no-spurious-wakeup tests. --- graal-js/test/test262.json | 126 +++++++++++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) diff --git a/graal-js/test/test262.json b/graal-js/test/test262.json index 6eb634554d1..c761d299224 100644 --- a/graal-js/test/test262.json +++ b/graal-js/test/test262.json @@ -155,6 +155,69 @@ "WINDOWS" : "SKIP" }, "comment" : "GR-22846" + }, { + "filePath" : "built-ins/Atomics/waitAsync/bigint/no-spurious-wakeup-no-operation.js", + "status" : "PASS", + "statusOverrides" : { + "WINDOWS" : "SKIP" + }, + "comment" : "GR-22846" + }, { + "filePath" : "built-ins/Atomics/waitAsync/bigint/no-spurious-wakeup-on-add.js", + "status" : "PASS", + "statusOverrides" : { + "WINDOWS" : "SKIP" + }, + "comment" : "GR-22846" + }, { + "filePath" : "built-ins/Atomics/waitAsync/bigint/no-spurious-wakeup-on-and.js", + "status" : "PASS", + "statusOverrides" : { + "WINDOWS" : "SKIP" + }, + "comment" : "GR-22846" + }, { + "filePath" : "built-ins/Atomics/waitAsync/bigint/no-spurious-wakeup-on-compareExchange.js", + "status" : "PASS", + "statusOverrides" : { + "WINDOWS" : "SKIP" + }, + "comment" : "GR-22846" + }, { + "filePath" : "built-ins/Atomics/waitAsync/bigint/no-spurious-wakeup-on-exchange.js", + "status" : "PASS", + "statusOverrides" : { + "WINDOWS" : "SKIP" + }, + "comment" : "GR-22846" + }, { + "filePath" : "built-ins/Atomics/waitAsync/bigint/no-spurious-wakeup-on-or.js", + "status" : "PASS", + "statusOverrides" : { + "WINDOWS" : "SKIP" + }, + "comment" : "GR-22846" + }, { + "filePath" : "built-ins/Atomics/waitAsync/bigint/no-spurious-wakeup-on-store.js", + "status" : "PASS", + "statusOverrides" : { + "WINDOWS" : "SKIP" + }, + "comment" : "GR-22846" + }, { + "filePath" : "built-ins/Atomics/waitAsync/bigint/no-spurious-wakeup-on-sub.js", + "status" : "PASS", + "statusOverrides" : { + "WINDOWS" : "SKIP" + }, + "comment" : "GR-22846" + }, { + "filePath" : "built-ins/Atomics/waitAsync/bigint/no-spurious-wakeup-on-xor.js", + "status" : "PASS", + "statusOverrides" : { + "WINDOWS" : "SKIP" + }, + "comment" : "GR-22846" }, { "filePath" : "built-ins/Atomics/waitAsync/bigint/true-for-timeout.js", "status" : "PASS", @@ -162,6 +225,69 @@ "COMPILE_IMMEDIATELY" : "SKIP" }, "comment" : "Contains a hard-coded timeout that is exceeded in CompileImmediately mode" + }, { + "filePath" : "built-ins/Atomics/waitAsync/no-spurious-wakeup-no-operation.js", + "status" : "PASS", + "statusOverrides" : { + "WINDOWS" : "SKIP" + }, + "comment" : "GR-22846" + }, { + "filePath" : "built-ins/Atomics/waitAsync/no-spurious-wakeup-on-add.js", + "status" : "PASS", + "statusOverrides" : { + "WINDOWS" : "SKIP" + }, + "comment" : "GR-22846" + }, { + "filePath" : "built-ins/Atomics/waitAsync/no-spurious-wakeup-on-and.js", + "status" : "PASS", + "statusOverrides" : { + "WINDOWS" : "SKIP" + }, + "comment" : "GR-22846" + }, { + "filePath" : "built-ins/Atomics/waitAsync/no-spurious-wakeup-on-compareExchange.js", + "status" : "PASS", + "statusOverrides" : { + "WINDOWS" : "SKIP" + }, + "comment" : "GR-22846" + }, { + "filePath" : "built-ins/Atomics/waitAsync/no-spurious-wakeup-on-exchange.js", + "status" : "PASS", + "statusOverrides" : { + "WINDOWS" : "SKIP" + }, + "comment" : "GR-22846" + }, { + "filePath" : "built-ins/Atomics/waitAsync/no-spurious-wakeup-on-or.js", + "status" : "PASS", + "statusOverrides" : { + "WINDOWS" : "SKIP" + }, + "comment" : "GR-22846" + }, { + "filePath" : "built-ins/Atomics/waitAsync/no-spurious-wakeup-on-store.js", + "status" : "PASS", + "statusOverrides" : { + "WINDOWS" : "SKIP" + }, + "comment" : "GR-22846" + }, { + "filePath" : "built-ins/Atomics/waitAsync/no-spurious-wakeup-on-sub.js", + "status" : "PASS", + "statusOverrides" : { + "WINDOWS" : "SKIP" + }, + "comment" : "GR-22846" + }, { + "filePath" : "built-ins/Atomics/waitAsync/no-spurious-wakeup-on-xor.js", + "status" : "PASS", + "statusOverrides" : { + "WINDOWS" : "SKIP" + }, + "comment" : "GR-22846" }, { "filePath" : "built-ins/Atomics/waitAsync/returns-result-object-value-is-promise-resolves-to-timed-out.js", "status" : "PASS", From 3914df7014650035dffd526b76f68bdb56435cd1 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 18 Jun 2024 05:37:02 +0200 Subject: [PATCH 107/265] Update testv8 status. --- graal-js/test/testV8.json | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/graal-js/test/testV8.json b/graal-js/test/testV8.json index 8e8859e2a9a..73e547809ed 100644 --- a/graal-js/test/testV8.json +++ b/graal-js/test/testV8.json @@ -1619,9 +1619,8 @@ "filePath" : "mjsunit/regress/regress-crbug-1412938.js", "status" : "SKIP", "statusOverrides" : { - "POLYGLOT" : "FAIL" - }, - "comment" : "new failures 2023-10-09" + "POLYGLOT" : "PASS" + } }, { "filePath" : "mjsunit/regress/regress-crbug-1415249.js", "status" : "FAIL", @@ -5225,9 +5224,8 @@ "filePath" : "mjsunit/wasm/ffi.js", "status" : "SKIP", "statusOverrides" : { - "POLYGLOT" : "FAIL" - }, - "comment" : "GR-53938: Error when importing one function from JS under different type signatures" + "POLYGLOT" : "PASS" + } }, { "filePath" : "mjsunit/wasm/float-constant-folding.js", "status" : "SKIP", @@ -5505,9 +5503,8 @@ "filePath" : "mjsunit/wasm/import-function.js", "status" : "SKIP", "statusOverrides" : { - "POLYGLOT" : "FAIL" - }, - "comment" : "GR-53938: The print function is imported twice in the same module, using different type signatures." + "POLYGLOT" : "PASS" + } }, { "filePath" : "mjsunit/wasm/import-memory.js", "status" : "SKIP", From 84a620a0758288931e6a6a2de8bcec0351a15cda Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 16 Jul 2024 16:50:21 +0200 Subject: [PATCH 108/265] Improve reporting of AggregateErrors in the REPL. --- .../oracle/truffle/js/shell/JSLauncher.java | 56 +++++++++++++++++-- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js.shell/src/com/oracle/truffle/js/shell/JSLauncher.java b/graal-js/src/com.oracle.truffle.js.shell/src/com/oracle/truffle/js/shell/JSLauncher.java index 84497190ade..aa9f82fac7e 100644 --- a/graal-js/src/com.oracle.truffle.js.shell/src/com/oracle/truffle/js/shell/JSLauncher.java +++ b/graal-js/src/com.oracle.truffle.js.shell/src/com/oracle/truffle/js/shell/JSLauncher.java @@ -396,7 +396,7 @@ private static int handlePolyglotException(PolyglotException e) { printError(e, System.err); status = 7; } else if (!e.isInternalError()) { - printStackTraceSkipTrailingHost(e, System.err); + printGuestException(e, System.err); status = 7; } else { e.printStackTrace(); @@ -433,7 +433,7 @@ private static int runREPL(Context context) { } else if (e.isSyntaxError()) { printError(e, System.err); } else if (!e.isInternalError()) { - printStackTraceSkipTrailingHost(e, System.err); + printGuestException(e, System.err); } else { e.printStackTrace(); return 8; @@ -459,7 +459,51 @@ private static void printError(Throwable e, PrintStream output) { } } - private static void printStackTraceSkipTrailingHost(PolyglotException e, PrintStream output) { + private static Value getErrorsFromAggregateError(Value guestException) { + if (guestException.hasMembers()) { + Value errorMetaObject = guestException.getMetaObject(); + if (errorMetaObject != null && "AggregateError".equals(errorMetaObject.getMetaSimpleName())) { + Value errors = guestException.getMember("errors"); + if (errors != null && errors.hasArrayElements()) { + return errors; + } + } + } + return null; + } + + private static void printGuestException(PolyglotException e, PrintStream err) { + StringBuilder output = new StringBuilder(); + printStackTraceSkipTrailingHost(e, output, ""); + Value guestException = e.getGuestObject(); + if (guestException != null && guestException.isException()) { + // Print all errors of an AggregateError + Value errors = getErrorsFromAggregateError(guestException); + if (errors != null) { + long size = errors.getArraySize(); + output.append(" {").append(System.lineSeparator()); + output.append(" [errors]: [").append(System.lineSeparator()); + String indent = " ".repeat(4); + for (long i = 0; i < size; i++) { + Value error = errors.getArrayElement(i); + if (error.isException()) { + printStackTraceSkipTrailingHost(error.as(PolyglotException.class), output, indent); + } else { + output.append(error.toString()); + } + if (i != size - 1) { + output.append(","); + } + output.append(System.lineSeparator()); + } + output.append(" ]").append(System.lineSeparator()); + output.append("}"); + } + } + err.println(output); + } + + private static void printStackTraceSkipTrailingHost(PolyglotException e, StringBuilder output, String indent) { List stackTrace = new ArrayList<>(); for (PolyglotException.StackFrame s : e.getPolyglotStackTrace()) { stackTrace.add(s); @@ -473,9 +517,11 @@ private static void printStackTraceSkipTrailingHost(PolyglotException e, PrintSt break; } } - output.println(e.isHostException() ? e.asHostException().toString() : e.getMessage()); + String message = e.isHostException() ? e.asHostException().toString() : e.getMessage(); + output.append(indent).append(message); for (PolyglotException.StackFrame s : stackTrace) { - output.println("\tat " + s); + output.append(System.lineSeparator()); + output.append(indent).append(" at ").append(s); } } From 874b8b9f70c912468a461520c181b944d9b464bc Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 17 Jul 2024 18:17:27 +0200 Subject: [PATCH 109/265] Test AggregateError printing in the js launcher/REPL. --- graal-js/ci.jsonnet | 2 +- graal-js/test/repl/aggregate-error.test | 44 +++++++++++++++++++ graal-js/test/repl/throw-aggregate-error.js | 10 +++++ .../repl/unhandled-rejections-primitive.js | 8 ++++ graal-js/test/repl/unhandled-rejections.js | 8 ++++ 5 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 graal-js/test/repl/aggregate-error.test create mode 100644 graal-js/test/repl/throw-aggregate-error.js create mode 100644 graal-js/test/repl/unhandled-rejections-primitive.js create mode 100644 graal-js/test/repl/unhandled-rejections.js diff --git a/graal-js/ci.jsonnet b/graal-js/ci.jsonnet index 0f406ddff76..c557d3163ac 100644 --- a/graal-js/ci.jsonnet +++ b/graal-js/ci.jsonnet @@ -108,7 +108,7 @@ local ci = import '../ci.jsonnet'; graalvmtests:: '../../graalvm-tests', run+: [ ['mx', 'build'], - ['python', '../../graalvm-tests/test.py', '-g', ['mx', '--quiet', 'graalvm-home'], '--print-revisions', '--keep-on-error', 'test/aux-engine-cache'], + ['python', '../../graalvm-tests/test.py', '-g', ['mx', '--quiet', 'graalvm-home'], '--print-revisions', '--keep-on-error', 'test/aux-engine-cache', 'test/repl'], ], timelimit: '1:00:00', }, diff --git a/graal-js/test/repl/aggregate-error.test b/graal-js/test/repl/aggregate-error.test new file mode 100644 index 00000000000..f9133bf6c70 --- /dev/null +++ b/graal-js/test/repl/aggregate-error.test @@ -0,0 +1,44 @@ +#/* +# * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. +# * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# * +# * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. +# */ +# +# ------ +# Test reporting of AggregateErrors in the `js` launcher/REPL. +# ------ +# To run: +# graal-js $ ../../graalvm-tests/test.py --keep-on-error -g $(mx --quiet graalvm-home) test/repl/aggregate-error.test +# graal-js $ ../../graalvm-tests/test.py --keep-on-error -g $(mx --quiet --dynamicimports /vm standalone-home js) test/repl/aggregate-error.test +# +>[7r] js --engine.WarnInterpreterOnly=false --unhandled-rejections=throw ${TEST_DIR}/throw-aggregate-error.js +AggregateError: dolor + at :program\(.*throw-aggregate-error.js:7.*\) \{ + \[errors\]: \[ + Error: lorem + at hoge\(.*throw-aggregate-error.js:8.*\) + at :program\(.*throw-aggregate-error.js:8.*\), + Error: ipsum + at fuga\(.*throw-aggregate-error.js:9.*\) + at :program\(.*throw-aggregate-error.js:9.*\) + \] +\} +>[7r] js --engine.WarnInterpreterOnly=false --unhandled-rejections=throw ${TEST_DIR}/unhandled-rejections.js +AggregateError: Unhandled promise rejections \{ + \[errors\]: \[ + Error: lorem + at hoge\(.*unhandled-rejections.js:7.*\) + at :program\(.*unhandled-rejections.js:7.*\), + Error: ipsum + at fuga\(.*unhandled-rejections.js:8.*\) + at :program\(.*unhandled-rejections.js:8.*\) + \] +\} +>[7] js --engine.WarnInterpreterOnly=false --unhandled-rejections=throw ${TEST_DIR}/unhandled-rejections-primitive.js +AggregateError: Unhandled promise rejections { + [errors]: [ + Error: Unhandled promise rejection: 42, + Error: Unhandled promise rejection: 211 + ] +} diff --git a/graal-js/test/repl/throw-aggregate-error.js b/graal-js/test/repl/throw-aggregate-error.js new file mode 100644 index 00000000000..088f82b8bf3 --- /dev/null +++ b/graal-js/test/repl/throw-aggregate-error.js @@ -0,0 +1,10 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ +throw new AggregateError([ + (function hoge(){ return new Error("lorem"); })(), + (function fuga(){ return new Error("ipsum"); })(), +], "dolor"); diff --git a/graal-js/test/repl/unhandled-rejections-primitive.js b/graal-js/test/repl/unhandled-rejections-primitive.js new file mode 100644 index 00000000000..fdb3949d8ff --- /dev/null +++ b/graal-js/test/repl/unhandled-rejections-primitive.js @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ +Promise.reject(42); +Promise.reject(211); diff --git a/graal-js/test/repl/unhandled-rejections.js b/graal-js/test/repl/unhandled-rejections.js new file mode 100644 index 00000000000..55f2792aa00 --- /dev/null +++ b/graal-js/test/repl/unhandled-rejections.js @@ -0,0 +1,8 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ +(function hoge(){ Promise.reject(new Error("lorem")); })(); +(function fuga(){ Promise.reject(new Error("ipsum")); })(); From 53e120b15658b9570803f20d185d9cc57c0796d5 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 18 Jul 2024 14:33:53 +0200 Subject: [PATCH 110/265] Use standalone distributions instead of legacy graalvm build for tests. --- graal-js/ci.jsonnet | 4 ++-- graal-nodejs/ci.jsonnet | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/graal-js/ci.jsonnet b/graal-js/ci.jsonnet index c557d3163ac..da846a5622c 100644 --- a/graal-js/ci.jsonnet +++ b/graal-js/ci.jsonnet @@ -107,8 +107,8 @@ local ci = import '../ci.jsonnet'; nativeimages+:: ['lib:jsvm'], graalvmtests:: '../../graalvm-tests', run+: [ - ['mx', 'build'], - ['python', '../../graalvm-tests/test.py', '-g', ['mx', '--quiet', 'graalvm-home'], '--print-revisions', '--keep-on-error', 'test/aux-engine-cache', 'test/repl'], + ['mx', 'build', '--dependencies', 'ALL_GRAALVM_ARTIFACTS'], + ['python', self.graalvmtests + '/test.py', '-g', ['mx', '--quiet', 'standalone-home', 'js'], '--print-revisions', '--keep-on-error', 'test/aux-engine-cache', 'test/repl'], ], timelimit: '1:00:00', }, diff --git a/graal-nodejs/ci.jsonnet b/graal-nodejs/ci.jsonnet index 21d9944faa6..5813e09e9ca 100644 --- a/graal-nodejs/ci.jsonnet +++ b/graal-nodejs/ci.jsonnet @@ -87,7 +87,7 @@ local cicommon = import '../ci/common.jsonnet'; local auxEngineCache = { graalvmtests:: '../../graalvm-tests', run+: [ - ['python', self.graalvmtests + '/test.py', '-g', ['mx', '--quiet', 'graalvm-home'], '--print-revisions', '--keep-on-error', 'test/graal/aux-engine-cache'], + ['python', self.graalvmtests + '/test.py', '-g', ['mx', '--quiet', 'standalone-home', 'nodejs'], '--print-revisions', '--keep-on-error', 'test/graal/aux-engine-cache'], ], timelimit: '1:00:00', }, From 05ca69a8339883f5ad3d91c13447347ca5b854ab Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Sun, 14 Jul 2024 18:42:03 +0200 Subject: [PATCH 111/265] Adding a note about Node.js update (to version 20.15.1) into change-log. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfdbf3516a3..9279224ddb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ Changelog may include unreleased versions. See [release calendar](https://www.graalvm.org/release-calendar/) for release dates. ## Version 24.2.0 +* Updated Node.js to version 20.15.1. * Implemented the [`Promise.try`](https://github.com/tc39/proposal-promise-try) proposal. It is available in ECMAScript staging mode (`--js.ecmascript-version=staging`). * Usage of non-standard extensions `Error.prepareStackTrace` and `Error.stackTraceLimit` has been limited to `js.v8-compat` mode only. From edec968740c0b28c36f1dfb95af7e41892f78f77 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Fri, 19 Jul 2024 17:21:52 +0200 Subject: [PATCH 112/265] Make AggregateError formatting more robust against errors. --- .../oracle/truffle/js/shell/JSLauncher.java | 48 +++++++++++-------- graal-js/test/repl/aggregate-error.test | 4 ++ .../repl/booby-trapped-aggregate-error.js | 12 +++++ 3 files changed, 43 insertions(+), 21 deletions(-) create mode 100644 graal-js/test/repl/booby-trapped-aggregate-error.js diff --git a/graal-js/src/com.oracle.truffle.js.shell/src/com/oracle/truffle/js/shell/JSLauncher.java b/graal-js/src/com.oracle.truffle.js.shell/src/com/oracle/truffle/js/shell/JSLauncher.java index aa9f82fac7e..bbf7dbc571f 100644 --- a/graal-js/src/com.oracle.truffle.js.shell/src/com/oracle/truffle/js/shell/JSLauncher.java +++ b/graal-js/src/com.oracle.truffle.js.shell/src/com/oracle/truffle/js/shell/JSLauncher.java @@ -460,7 +460,7 @@ private static void printError(Throwable e, PrintStream output) { } private static Value getErrorsFromAggregateError(Value guestException) { - if (guestException.hasMembers()) { + if (guestException.isException() && guestException.hasMembers()) { Value errorMetaObject = guestException.getMetaObject(); if (errorMetaObject != null && "AggregateError".equals(errorMetaObject.getMetaSimpleName())) { Value errors = guestException.getMember("errors"); @@ -476,28 +476,34 @@ private static void printGuestException(PolyglotException e, PrintStream err) { StringBuilder output = new StringBuilder(); printStackTraceSkipTrailingHost(e, output, ""); Value guestException = e.getGuestObject(); - if (guestException != null && guestException.isException()) { - // Print all errors of an AggregateError - Value errors = getErrorsFromAggregateError(guestException); - if (errors != null) { - long size = errors.getArraySize(); - output.append(" {").append(System.lineSeparator()); - output.append(" [errors]: [").append(System.lineSeparator()); - String indent = " ".repeat(4); - for (long i = 0; i < size; i++) { - Value error = errors.getArrayElement(i); - if (error.isException()) { - printStackTraceSkipTrailingHost(error.as(PolyglotException.class), output, indent); - } else { - output.append(error.toString()); - } - if (i != size - 1) { - output.append(","); + if (guestException != null) { + int safeLength = output.length(); + try { + // Print all errors of an AggregateError + Value errors = getErrorsFromAggregateError(guestException); + if (errors != null) { + long size = errors.getArraySize(); + output.append(" {").append(System.lineSeparator()); + output.append(" [errors]: [").append(System.lineSeparator()); + String indent = " ".repeat(4); + for (long i = 0; i < size; i++) { + Value error = errors.getArrayElement(i); + if (error.isException()) { + printStackTraceSkipTrailingHost(error.as(PolyglotException.class), output, indent); + } else { + output.append(error.toString()); + } + if (i != size - 1) { + output.append(","); + } + output.append(System.lineSeparator()); } - output.append(System.lineSeparator()); + output.append(" ]").append(System.lineSeparator()); + output.append("}"); } - output.append(" ]").append(System.lineSeparator()); - output.append("}"); + } catch (PolyglotException ignored) { + // Erase any incomplete output. + output.setLength(safeLength); } } err.println(output); diff --git a/graal-js/test/repl/aggregate-error.test b/graal-js/test/repl/aggregate-error.test index f9133bf6c70..06f90c21e1c 100644 --- a/graal-js/test/repl/aggregate-error.test +++ b/graal-js/test/repl/aggregate-error.test @@ -42,3 +42,7 @@ AggregateError: Unhandled promise rejections { Error: Unhandled promise rejection: 211 ] } +>[7] js --engine.WarnInterpreterOnly=false --unhandled-rejections=throw ${TEST_DIR}/booby-trapped-aggregate-error.js +Error + at AggregateError\(.*booby-trapped-aggregate-error.js:7.*\) + at :program\(.*booby-trapped-aggregate-error.js:12.*\) diff --git a/graal-js/test/repl/booby-trapped-aggregate-error.js b/graal-js/test/repl/booby-trapped-aggregate-error.js new file mode 100644 index 00000000000..f81dc1db460 --- /dev/null +++ b/graal-js/test/repl/booby-trapped-aggregate-error.js @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ +class AggregateError extends Error { + get errors() { + throw new Error('surprise'); + } +} +throw new AggregateError([]); From 396b1ef69eb51b91e16c60d91b64a22af1637941 Mon Sep 17 00:00:00 2001 From: Olya Gupalo Date: Mon, 22 Jul 2024 09:50:53 +0300 Subject: [PATCH 113/265] Update FAQ.md --- docs/user/FAQ.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/user/FAQ.md b/docs/user/FAQ.md index b9b48f81571..360ceb726bf 100644 --- a/docs/user/FAQ.md +++ b/docs/user/FAQ.md @@ -257,13 +257,13 @@ If you get the following warning, you are not running on GraalVM JDK, or a compa ``` [engine] WARNING: The polyglot context is using an implementation that does not support runtime compilation. The guest application code will therefore be executed in interpreted mode only. -Execution only in interpreted mode will strongly impact the guest application performance. -To disable this warning the '--engine.WarnInterpreterOnly=false' option or use the '-Dpolyglot.engine.WarnInterpreterOnly=false' system property. +Execution only in interpreted mode will strongly impair guest application performance. +To disable this warning, use the '--engine.WarnInterpreterOnly=false' option or the '-Dpolyglot.engine.WarnInterpreterOnly=false' system property. ``` -To resolve this, use [GraalVM](https://github.com/oracle/graal/blob/master/docs/getting-started/graalvm-community/get-started-graalvm-community.md) or see the [Run GraalVM JavaScript on a Stock JDK guide](RunOnJDK.md) for instructions how to set up the Graal compiler on a compatible Graal-enabled stock JDK. +To resolve this issue, use [GraalVM](https://www.graalvm.org/downloads/) or see the [Run GraalVM JavaScript on a Stock JDK guide](RunOnJDK.md) for instructions how to set up the Graal JIT compiler on a compatible Graal-enabled stock JDK. -Nevertheless, if this is intentional, you can disable the warning and continue to run with degraded performance by setting the above mentioned option, either via the command line or using the `Context.Builder`, e.g.: +Nevertheless, if this is intentional, you can disable the warning and continue to run with degraded performance by setting the option described above, either via the command line or by using the `Context.Builder`, for example: ```java try (Context ctx = Context.newBuilder("js") .option("engine.WarnInterpreterOnly", "false") @@ -271,7 +271,7 @@ try (Context ctx = Context.newBuilder("js") ctx.eval("js", "console.log('Greetings!');"); } ``` -Note that when using an explicit polyglot engine, the option has to be set on the `Engine`, e.g.: +Note that when using an explicit polyglot engine, the option has to be set on the `Engine`, for example: ```java try (Engine engine = Engine.newBuilder() .option("engine.WarnInterpreterOnly", "false") From f2891a2b3c7889f3f2e9301b3ae941c47bb679cf Mon Sep 17 00:00:00 2001 From: Jirka Marsik Date: Mon, 22 Jul 2024 09:55:09 +0200 Subject: [PATCH 114/265] Check lastIndex bounds in ES5's string.match(/re/g) --- .../js/github_graaljs_835.js | 16 ++++++++++++++++ .../js/builtins/StringPrototypeBuiltins.java | 19 ++++++++----------- .../truffle/js/nodes/cast/JSToRegExpNode.java | 4 ++-- 3 files changed, 26 insertions(+), 13 deletions(-) create mode 100644 graal-js/src/com.oracle.truffle.js.test/js/github_graaljs_835.js diff --git a/graal-js/src/com.oracle.truffle.js.test/js/github_graaljs_835.js b/graal-js/src/com.oracle.truffle.js.test/js/github_graaljs_835.js new file mode 100644 index 00000000000..3a17fbdeb3c --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/js/github_graaljs_835.js @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ + +/** + * @option nashorn-compat=true + */ + +load('assert.js'); + +assertSameContent(["", "", ""], "10".match(/a*/g)); +assertSameContent(["", ""], "10".match(/$/g)); +assertSameContent(["0", ""], "10".match(/0*$/g)); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/StringPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/StringPrototypeBuiltins.java index f06436d78c0..e71894fbe7c 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/StringPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/StringPrototypeBuiltins.java @@ -2351,7 +2351,7 @@ private int indexOf(TruffleString a, int codepoint) { /** * Implementation of the String.prototype.match() method as specified by ECMAScript 5.1 in - * 15.5.4.19. + * 15.5.4.10. */ public abstract static class JSStringMatchES5Node extends JSStringOperationWithRegExpArgument { @Child private PropertySetNode setLastIndexNode; @@ -2359,7 +2359,6 @@ public abstract static class JSStringMatchES5Node extends JSStringOperationWithR public JSStringMatchES5Node(JSContext context, JSBuiltin builtin) { super(context, builtin); assert context.getEcmaScriptVersion() < 6; - } private void setLastIndex(JSDynamicObject regExp, int value) { @@ -2371,7 +2370,7 @@ private void setLastIndex(JSDynamicObject regExp, int value) { } @Specialization - protected JSDynamicObject matchRegExpNotGlobal(Object thisObj, Object searchObj, + protected JSDynamicObject match(Object thisObj, Object searchObj, @Cached("create(getContext())") JSToRegExpNode toRegExpNode, @Cached("create(getContext())") JSRegExpExecES5Node regExpExecNode, @Cached InlinedCountingConditionProfile isMatch, @@ -2382,12 +2381,12 @@ protected JSDynamicObject matchRegExpNotGlobal(Object thisObj, Object searchObj, @Cached(inline = true) TRegexUtil.InvokeGetGroupBoundariesMethodNode getEnd, @Cached TRegexUtil.TRegexCompiledRegexSingleFlagAccessorNode getGlobalFlag) { requireObjectCoercible(thisObj); + TruffleString thisStr = toString(thisObj); if (isGlobalRegExp.profile(this, JSRegExp.isJSRegExp(searchObj) && isGlobal(JSRegExp.getCompiledRegex((JSRegExpObject) searchObj), getGlobalFlag))) { - TruffleString thisStr = toString(thisObj); - return matchAll((JSRegExpObject) searchObj, thisStr, + return matchGlobal(thisStr, (JSRegExpObject) searchObj, this, isMatch, substringNode, readIsMatch, getStart, getEnd); } else { - return matchNotRegExpIntl(thisObj, searchObj, toRegExpNode, regExpExecNode); + return matchNotGlobal(thisStr, searchObj, toRegExpNode, regExpExecNode); } } @@ -2395,14 +2394,13 @@ private boolean isGlobal(Object compiledRegex, TRegexUtil.TRegexCompiledRegexSin return getGlobalFlag.execute(this, compiledRegex, TRegexUtil.Props.Flags.GLOBAL); } - private JSDynamicObject matchNotRegExpIntl(Object thisObj, Object searchObj, + private static JSDynamicObject matchNotGlobal(TruffleString thisStr, Object searchObj, JSToRegExpNode toRegExpNode, JSRegExpExecES5Node regExpExecNode) { - Object thisStr = toString(thisObj); JSRegExpObject regExp = toRegExpNode.execute(searchObj); return regExpExecNode.execute(regExp, thisStr); } - private JSDynamicObject matchAll(JSRegExpObject regExp, TruffleString input, + private JSDynamicObject matchGlobal(TruffleString input, JSRegExpObject regExp, Node node, InlinedCountingConditionProfile isMatch, @Cached TruffleString.SubstringByteIndexNode substringNode, @@ -2421,11 +2419,10 @@ private JSDynamicObject matchAll(JSRegExpObject regExp, TruffleString input, int thisIndex = TRegexResultAccessor.captureGroupEnd(result, 0, node, getEnd); lastIndex = thisIndex + (thisIndex == lastIndex ? 1 : 0); - result = matchIgnoreLastIndex(regExp, input, lastIndex); + result = lastIndex > Strings.length(input) ? getContext().getTRegexEmptyResult() : matchIgnoreLastIndex(regExp, input, lastIndex); } return JSArray.createConstant(getContext(), getRealm(), Boundaries.listToArray(matches)); } - } /** diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/cast/JSToRegExpNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/cast/JSToRegExpNode.java index 749fe424698..4af88e680a9 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/cast/JSToRegExpNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/cast/JSToRegExpNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -50,7 +50,7 @@ import com.oracle.truffle.js.runtime.builtins.JSRegExpObject; /** - * Implements a cast from an value to a RegExp Object, as defined by String.prototype.match and + * Implements a cast from a value to a RegExp Object, as defined by String.prototype.match and * String.prototype.search. */ public abstract class JSToRegExpNode extends JavaScriptBaseNode { From 91829eeb62a25b08ce2e7702292268c3dc1d3639 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 24 Jul 2024 15:54:09 +0200 Subject: [PATCH 115/265] Improve error message for when imported module is not an object. --- .../wasm/GR-56110.js | 26 +++++++++++++++++++ .../builtins/wasm/JSWebAssemblyInstance.java | 4 +-- 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 graal-js/src/com.oracle.truffle.js.test/wasm/GR-56110.js diff --git a/graal-js/src/com.oracle.truffle.js.test/wasm/GR-56110.js b/graal-js/src/com.oracle.truffle.js.test/wasm/GR-56110.js new file mode 100644 index 00000000000..576208cb1fb --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/wasm/GR-56110.js @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ + +/** + * Test error messages for missing importObject keys or illegal values. + * + * @option webassembly + */ + +load('../js/assert.js'); + +//(module +// (type (func (result i32))) +// (import "m" "f" (func (type 0))) +//) +const bytes = new Uint8Array([ + 0x0,0x61,0x73,0x6d,0x1,0x0,0x0,0x0, + 0x1,0x5,0x1,0x60,0x0,0x1,0x7f, + 0x2,0x7,0x1,0x1,0x6d,0x1,0x66,0x0,0x0]); + +const wasmModule = new WebAssembly.Module(bytes); +assertThrows(() => new WebAssembly.Instance(wasmModule, {}), TypeError, 'Imported module "m" is not an object'); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyInstance.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyInstance.java index 9ccf26f4526..4767619c86f 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyInstance.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyInstance.java @@ -269,7 +269,7 @@ public Object execute(VirtualFrame frame) { @CompilerDirectives.TruffleBoundary public static Object transformImportObject(JSContext context, JSRealm realm, Object wasmModule, Object importObject) { try { - JSDynamicObject transformedImportObject = JSOrdinary.createWithNullPrototype(context); + JSObject transformedImportObject = JSOrdinary.createWithNullPrototype(context); Object importsFn = realm.getWASMModuleImports(); Object imports = InteropLibrary.getUncached(importsFn).execute(importsFn, wasmModule); @@ -283,7 +283,7 @@ public static Object transformImportObject(JSContext context, JSRealm realm, Obj Object moduleImportObject = JSRuntime.get(importObject, module); InteropLibrary moduleImportObjectInterop = InteropLibrary.getUncached(moduleImportObject); if (!moduleImportObjectInterop.hasMembers(moduleImportObject)) { - throw Errors.createTypeErrorNotAnObject(moduleImportObject); + throw Errors.createTypeError("Imported module \"" + module + "\" is not an object: " + JSRuntime.safeToString(moduleImportObject)); } TruffleString name = asTString(descriptorInterop.readMember(descriptor, "name")); From c262a5b353ad0afb538a6ba7cb8a838b2e982982 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Fri, 26 Jul 2024 15:09:27 +0200 Subject: [PATCH 116/265] Improve error message for when imported value is not of the required type. --- .../wasm/GR-56110.js | 3 +++ .../builtins/wasm/JSWebAssemblyInstance.java | 22 ++++++++++++------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js.test/wasm/GR-56110.js b/graal-js/src/com.oracle.truffle.js.test/wasm/GR-56110.js index 576208cb1fb..cdb8d15b9d5 100644 --- a/graal-js/src/com.oracle.truffle.js.test/wasm/GR-56110.js +++ b/graal-js/src/com.oracle.truffle.js.test/wasm/GR-56110.js @@ -24,3 +24,6 @@ const bytes = new Uint8Array([ const wasmModule = new WebAssembly.Module(bytes); assertThrows(() => new WebAssembly.Instance(wasmModule, {}), TypeError, 'Imported module "m" is not an object'); + +assertThrows(() => new WebAssembly.Instance(wasmModule, {m: {}}), WebAssembly.LinkError, 'Import #0 "m" "f": Imported value is not callable'); +assertThrows(() => new WebAssembly.Instance(wasmModule, {m: {f: 404}}), WebAssembly.LinkError, 'Import #0 "m" "f": Imported value is not callable'); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyInstance.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyInstance.java index 4767619c86f..8797fa07f4d 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyInstance.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyInstance.java @@ -62,6 +62,7 @@ import com.oracle.truffle.js.runtime.JSArguments; import com.oracle.truffle.js.runtime.JSConfig; import com.oracle.truffle.js.runtime.JSContext; +import com.oracle.truffle.js.runtime.JSException; import com.oracle.truffle.js.runtime.JSRealm; import com.oracle.truffle.js.runtime.JSRuntime; import com.oracle.truffle.js.runtime.JavaScriptRootNode; @@ -293,7 +294,7 @@ public static Object transformImportObject(JSContext context, JSRealm realm, Obj if (Strings.equals(Strings.FUNCTION, externType)) { if (!JSRuntime.isCallable(value)) { - throw Errors.createLinkError("Imported value is not callable"); + throw createLinkErrorImport(i, module, name, "Imported value is not callable"); } if (JSWebAssembly.isExportedFunction(value)) { wasmValue = JSWebAssembly.getExportedFunction((JSDynamicObject) value); @@ -308,16 +309,16 @@ public static Object transformImportObject(JSContext context, JSRealm realm, Obj TruffleString valueType = asTString(descriptorInterop.readMember(descriptor, "type")); boolean isI64 = JSWebAssemblyValueTypes.isI64(valueType); if (!context.getLanguageOptions().wasmBigInt() && isI64) { - throw Errors.createLinkError("Can't import the value of i64 WebAssembly.Global"); + throw createLinkErrorImport(i, module, name, "Can't import the value of i64 WebAssembly.Global"); } if (isI64 && isNumber) { - throw Errors.createLinkError("Value of valtype i64 must be BigInt"); + throw createLinkErrorImport(i, module, name, "Value of valtype i64 must be BigInt"); } if (!isI64 && isBigInt) { - throw Errors.createLinkError("BigInt can only be stored in valtype i64"); + throw createLinkErrorImport(i, module, name, "BigInt can only be stored in valtype i64"); } if (JSWebAssemblyValueTypes.isV128(valueType)) { - throw Errors.createLinkError("Values of valtype v128 cannot be imported from JS"); + throw createLinkErrorImport(i, module, name, "Values of valtype v128 cannot be imported from JS"); } Object webAssemblyValue = ToWebAssemblyValueNodeGen.getUncached().execute(value, valueType); try { @@ -329,20 +330,20 @@ public static Object transformImportObject(JSContext context, JSRealm realm, Obj } else if (JSWebAssemblyGlobal.isJSWebAssemblyGlobal(value)) { wasmValue = ((JSWebAssemblyGlobalObject) value).getWASMGlobal(); } else { - throw Errors.createLinkError("Imported value is not WebAssembly.Global object"); + throw createLinkErrorImport(i, module, name, "Imported value is not a WebAssembly.Global object"); } } else if (Strings.equals(Strings.MEMORY, externType)) { if (JSWebAssemblyMemory.isJSWebAssemblyMemory(value)) { wasmValue = ((JSWebAssemblyMemoryObject) value).getWASMMemory(); } else { - throw Errors.createLinkError("Imported value is not WebAssembly.Memory object"); + throw createLinkErrorImport(i, module, name, "Imported value is not a WebAssembly.Memory object"); } } else { assert Strings.equals(Strings.TABLE, externType) : externType; if (JSWebAssemblyTable.isJSWebAssemblyTable(value)) { wasmValue = ((JSWebAssemblyTableObject) value).getWASMTable(); } else { - throw Errors.createLinkError("Imported value is not WebAssembly.Table object"); + throw createLinkErrorImport(i, module, name, "Imported value is not a WebAssembly.Table object"); } } @@ -361,6 +362,11 @@ public static Object transformImportObject(JSContext context, JSRealm realm, Obj } } + @TruffleBoundary + private static JSException createLinkErrorImport(long index, TruffleString module, TruffleString name, String message) { + return Errors.createLinkError("Import #" + index + " \"" + module + "\" \"" + name + "\": " + message); + } + @TruffleBoundary private static Object createHostFunction(JSContext context, Object fn, TruffleString typeInfo) { return new WebAssemblyHostFunction(context, fn, typeInfo); From 79645933218ed69164a4035a5a1b0b0d80848dbf Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Fri, 26 Jul 2024 18:53:39 +0200 Subject: [PATCH 117/265] Remove obsolete message. --- .../src/com/oracle/truffle/js/runtime/JSRealm.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java index edb63bc1be1..d4d288dc75e 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java @@ -917,9 +917,6 @@ protected JSRealm(JSContext context, TruffleLanguage.Env env, JSRealm parentReal if (context.getLanguageOptions().webAssembly()) { if (!isWasmAvailable()) { String msg = "WebAssembly API enabled but wasm language cannot be accessed! Did you forget to set the --polyglot flag?"; - if (JSConfig.SubstrateVM) { - msg += " In native mode, you might have to rebuild libpolyglot with 'gu rebuild-images libpolyglot'."; - } throw new IllegalStateException(msg); } LanguageInfo wasmLanguageInfo = truffleLanguageEnv.getInternalLanguages().get("wasm"); From e812274b11ce9925b70b883f8bf71b0f9c90c007 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 26 Jul 2024 21:04:56 +0000 Subject: [PATCH 118/265] Update graal import. --- graal-js/mx.graal-js/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/mx.graal-js/suite.py b/graal-js/mx.graal-js/suite.py index 917b73d6510..9c44cdc5f6e 100644 --- a/graal-js/mx.graal-js/suite.py +++ b/graal-js/mx.graal-js/suite.py @@ -24,7 +24,7 @@ { "name" : "regex", "subdir" : True, - "version" : "1b5b284ffb425c5479be7c36d8813996249945b8", + "version" : "4e556c114c931e03795824268585286ea32f86cc", "urls" : [ {"url" : "https://github.com/oracle/graal.git", "kind" : "git"}, ] From c5e01a2264e37c6a38ae1e615232898dc4a679e2 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 26 Jul 2024 21:04:57 +0000 Subject: [PATCH 119/265] Sync CI files. --- common.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/common.json b/common.json index 18b166ffc31..83df74ca1ca 100644 --- a/common.json +++ b/common.json @@ -4,11 +4,11 @@ "Jsonnet files should not include this file directly but use ci/common.jsonnet instead." ], - "mx_version": "7.27.5", + "mx_version": "7.28.0", "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { - "galahad-jdk": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+5-437", "platformspecific": true, "extrabundles": ["static-libs"]}, + "galahad-jdk": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+6-612", "platformspecific": true, "extrabundles": ["static-libs"]}, "oraclejdk11": {"name": "jpg-jdk", "version": "11.0.11", "build_id": "jdk-11.0.11+9", "platformspecific": true, "extrabundles": ["static-libs"] }, @@ -45,13 +45,13 @@ "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.2+13-jvmci-23.1-b33-sulong", "platformspecific": true }, "graalvm-ee-21": {"name": "graalvm-java21", "version": "23.1.3", "platformspecific": true }, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+5", "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+5-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+5-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+5-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+5-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+5-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+5-jvmci-b01-sulong", "platformspecific": true } + "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+7", "platformspecific": true, "extrabundles": ["static-libs"]}, + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+7-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+7-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+7-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+7-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+7-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+7-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { From 4db05b0ebaf0e239ef18adb0ae2c3e991feee5a7 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 29 Jul 2024 15:55:46 +0200 Subject: [PATCH 120/265] [GR-56550] Fix sorting contiguous int and double arrays with holes at the end. --- .../com.oracle.truffle.js.test/js/GR-56550.js | 21 +++++++++++++ .../array/JSArrayToDenseObjectArrayNode.java | 31 ++++++++++--------- 2 files changed, 37 insertions(+), 15 deletions(-) create mode 100644 graal-js/src/com.oracle.truffle.js.test/js/GR-56550.js diff --git a/graal-js/src/com.oracle.truffle.js.test/js/GR-56550.js b/graal-js/src/com.oracle.truffle.js.test/js/GR-56550.js new file mode 100644 index 00000000000..3559995f4b4 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/js/GR-56550.js @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ + +/** + * Test sorting int and double arrays with hole elements at the end. + */ + +const v1 = [981517771,-1337791284,7,4096,8,64,10]; +const v2 = [1000000.0,-435.92083294324425,-4.0,-72924.4167712992,-166.99785787478345,0.7783900556580967,998508.9254321649,223.77879728853213]; + +v1.sort().shift(); +v1.length ^= 512; +v1.sort().shift(); + +v2.sort().shift(); +v2.length ^= 512; +v2.sort().shift(); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/JSArrayToDenseObjectArrayNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/JSArrayToDenseObjectArrayNode.java index ac4fe394e21..689f7675b8e 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/JSArrayToDenseObjectArrayNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/JSArrayToDenseObjectArrayNode.java @@ -50,7 +50,7 @@ import com.oracle.truffle.js.nodes.access.ReadElementNode; import com.oracle.truffle.js.runtime.JSRuntime; import com.oracle.truffle.js.runtime.array.ScriptArray; -import com.oracle.truffle.js.runtime.objects.JSDynamicObject; +import com.oracle.truffle.js.runtime.builtins.JSArrayObject; import com.oracle.truffle.js.runtime.util.SimpleArrayList; /** @@ -64,26 +64,27 @@ public abstract class JSArrayToDenseObjectArrayNode extends JavaScriptBaseNode { protected JSArrayToDenseObjectArrayNode() { } - public abstract Object[] executeObjectArray(JSDynamicObject array, ScriptArray arrayType, long length); + public abstract Object[] executeObjectArray(JSArrayObject array, ScriptArray arrayType, long length); - @Specialization(guards = {"cachedArrayType.isInstance(arrayType)", "!cachedArrayType.isHolesType()", "!cachedArrayType.hasHoles(array)", - "cachedArrayType.firstElementIndex(array)==0"}, limit = "5") - protected static Object[] fromDenseArray(JSDynamicObject array, @SuppressWarnings("unused") ScriptArray arrayType, long length, + @Specialization(guards = {"cachedArrayType.isInstance(arrayType)", "!cachedArrayType.isHolesType()"}, limit = "5") + protected static Object[] fromDenseArray(JSArrayObject array, @SuppressWarnings("unused") ScriptArray arrayType, long length, @Cached("arrayType") @SuppressWarnings("unused") ScriptArray cachedArrayType, @Cached("create(getJSContext())") @Shared ReadElementNode readNode) { assert JSRuntime.longIsRepresentableAsInt(length); - int iLen = (int) length; - - Object[] arr = new Object[iLen]; - for (int index = 0; index < iLen; index++) { - Object value = readNode.executeWithTargetAndIndex(array, index); - arr[index] = value; + long start = cachedArrayType.firstElementIndex(array); + long end = cachedArrayType.lastElementIndex(array) + 1; + Object[] arr = new Object[(int) (end - start)]; + int toIndex = 0; + for (long fromIndex = start; fromIndex < end; fromIndex++) { + assert cachedArrayType.hasElement(array, fromIndex); + Object value = readNode.executeWithTargetAndIndex(array, fromIndex); + arr[toIndex++] = value; } return arr; } - @Specialization(guards = {"cachedArrayType.isInstance(arrayType)", "cachedArrayType.isHolesType() || cachedArrayType.hasHoles(array)"}, limit = "5") - protected static Object[] fromSparseArray(JSDynamicObject array, @SuppressWarnings("unused") ScriptArray arrayType, long length, + @Specialization(guards = {"cachedArrayType.isInstance(arrayType)", "cachedArrayType.isHolesType()"}, limit = "5") + protected static Object[] fromSparseArray(JSArrayObject array, @SuppressWarnings("unused") ScriptArray arrayType, long length, @Cached("arrayType") @SuppressWarnings("unused") ScriptArray cachedArrayType, @Bind("this") Node node, @Cached("create(getJSContext())") @Shared JSArrayNextElementIndexNode nextElementIndexNode, @@ -99,11 +100,11 @@ protected static Object[] fromSparseArray(JSDynamicObject array, @SuppressWarnin } @Specialization(replaces = {"fromDenseArray", "fromSparseArray"}) - protected Object[] doUncached(JSDynamicObject array, ScriptArray arrayType, long length, + protected Object[] doUncached(JSArrayObject array, ScriptArray arrayType, long length, @Cached("create(getJSContext())") @Shared JSArrayNextElementIndexNode nextElementIndexNode, @Cached("create(getJSContext())") @Shared ReadElementNode readNode, @Cached @Shared InlinedBranchProfile growProfile) { - if (arrayType.isHolesType() || arrayType.hasHoles(array) || arrayType.firstElementIndex(array) != 0) { + if (arrayType.isHolesType()) { return fromSparseArray(array, arrayType, length, arrayType, this, nextElementIndexNode, growProfile); } else { return fromDenseArray(array, arrayType, length, arrayType, readNode); From 9e9df3100d3874e3d03111d91b69ecf63d77cbeb Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 18 Jul 2024 18:15:55 +0200 Subject: [PATCH 121/265] Use TruffleString.ToJavaStringNode in foreign property Get. --- .../oracle/truffle/js/nodes/access/PropertyGetNode.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/PropertyGetNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/PropertyGetNode.java index 52153df0936..004240f8996 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/PropertyGetNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/PropertyGetNode.java @@ -1116,6 +1116,7 @@ public static final class ForeignPropertyGetNode extends LinkedPropertyGetNode { private final JSContext context; @Child private InteropLibrary interop; @Child private InteropLibrary getterInterop; + @Child private TruffleString.ToJavaStringNode toJavaStringNode = TruffleString.ToJavaStringNode.create(); private final BranchProfile errorBranch = BranchProfile.create(); @CompilationFinal private boolean optimistic = true; @@ -1159,7 +1160,7 @@ private Object getImpl(Object thisObj, Object key, PropertyGetNode root) { return result; } } - String stringKey = Strings.toJavaString(propertyName); + String stringKey = Strings.toJavaString(toJavaStringNode, propertyName); if (optimistic) { try { return interop.readMember(thisObj, stringKey); @@ -1232,11 +1233,11 @@ private Object tryInvokeGetter(Object thisObj, TruffleString prefix, PropertyGet CompilerDirectives.transferToInterpreterAndInvalidate(); getterInterop = insert(InteropLibrary.getFactory().createDispatched(JSConfig.InteropLibraryLimit)); } - if (!getterInterop.isMemberInvocable(thisObj, Strings.toJavaString(getterKey))) { + if (!getterInterop.isMemberInvocable(thisObj, Strings.toJavaString(toJavaStringNode, getterKey))) { return null; } try { - return getterInterop.invokeMember(thisObj, Strings.toJavaString(getterKey), JSArguments.EMPTY_ARGUMENTS_ARRAY); + return getterInterop.invokeMember(thisObj, Strings.toJavaString(toJavaStringNode, getterKey), JSArguments.EMPTY_ARGUMENTS_ARRAY); } catch (UnknownIdentifierException | UnsupportedMessageException | UnsupportedTypeException | ArityException e) { return null; // try the next fallback } From 63afec34ca2bda63f1acb1bb7e9ad9e5a402f1f3 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 18 Jul 2024 18:17:29 +0200 Subject: [PATCH 122/265] Use TruffleString.FromLongNode in JSToStringNode. --- .../js/nodes/cast/JSDoubleToStringNode.java | 4 ++++ .../truffle/js/nodes/cast/JSToStringNode.java | 14 +++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/cast/JSDoubleToStringNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/cast/JSDoubleToStringNode.java index db7687fbe9e..674a383ca97 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/cast/JSDoubleToStringNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/cast/JSDoubleToStringNode.java @@ -59,6 +59,10 @@ public abstract class JSDoubleToStringNode extends JavaScriptBaseNode { public abstract TruffleString executeString(Object operand); + public abstract TruffleString executeString(double operand); + + public abstract TruffleString executeString(long operand); + @Specialization protected static TruffleString doInt(int i, @Cached @Shared TruffleString.FromLongNode fromLongNode) { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/cast/JSToStringNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/cast/JSToStringNode.java index 0c80d6425dc..a3414292949 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/cast/JSToStringNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/cast/JSToStringNode.java @@ -125,9 +125,11 @@ protected TruffleString doBoolean(boolean value) { return JSRuntime.booleanToString(value); } + @InliningCutoff @Specialization - protected TruffleString doInteger(int value) { - return Strings.fromInt(value); + protected TruffleString doInteger(int value, + @Shared @Cached JSDoubleToStringNode doubleToStringNode) { + return doubleToStringNode.executeString(value); } @Specialization @@ -135,15 +137,17 @@ protected TruffleString doBigInt(BigInt value) { return Strings.fromBigInt(value); } + @InliningCutoff @Specialization - protected TruffleString doLong(long value) { - return Strings.fromLong(value); + protected TruffleString doLong(long value, + @Shared @Cached JSDoubleToStringNode doubleToStringNode) { + return doubleToStringNode.executeString(value); } @InliningCutoff @Specialization protected TruffleString doDouble(double d, - @Cached JSDoubleToStringNode doubleToStringNode) { + @Shared @Cached JSDoubleToStringNode doubleToStringNode) { return doubleToStringNode.executeString(d); } From cb888c6c2fbea16a0254361aaa17bd66b1808d93 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 18 Jul 2024 18:37:54 +0200 Subject: [PATCH 123/265] Use TruffleStringBuilder nodes for print() and console.log(). --- .../truffle/js/builtins/GlobalBuiltins.java | 35 +++++++++++-------- .../js/runtime/util/StringBuilderProfile.java | 15 ++++++++ 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/GlobalBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/GlobalBuiltins.java index 6c9921b9240..e6bdb376512 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/GlobalBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/GlobalBuiltins.java @@ -84,6 +84,7 @@ import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.strings.TruffleString; +import com.oracle.truffle.api.strings.TruffleStringBuilder; import com.oracle.truffle.api.strings.TruffleStringBuilderUTF16; import com.oracle.truffle.js.builtins.GlobalBuiltinsFactory.GlobalNashornExtensionParseToJSONNodeGen; import com.oracle.truffle.js.builtins.GlobalBuiltinsFactory.GlobalScriptingEXECNodeGen; @@ -148,6 +149,7 @@ import com.oracle.truffle.js.runtime.objects.PropertyProxy; import com.oracle.truffle.js.runtime.objects.ScriptOrModule; import com.oracle.truffle.js.runtime.objects.Undefined; +import com.oracle.truffle.js.runtime.util.StringBuilderProfile; /** * Contains builtins for the global object. @@ -1363,35 +1365,38 @@ public JSGlobalPrintNode(JSContext context, JSBuiltin builtin, boolean useErr, b @Specialization protected Object print(Object[] arguments, @Cached InlinedConditionProfile argumentsCount, - @Cached InlinedBranchProfile consoleIndentation) { + @Cached(parameters = "getContext().getStringLengthLimit()") StringBuilderProfile builderProfile, + @Cached TruffleStringBuilder.AppendCodePointNode appendCodePointNode, + @Cached TruffleStringBuilder.AppendStringNode appendStringNode, + @Cached TruffleStringBuilder.ToStringNode toStringNode) { // without a StringBuilder, synchronization fails testnashorn JDK-8041998.js - var builder = Strings.builderCreate(); - JSConsoleUtil consoleUtil = getRealm().getConsoleUtil(); + JSRealm realm = getRealm(); + TruffleStringBuilderUTF16 sb = builderProfile.newStringBuilder(); + JSConsoleUtil consoleUtil = realm.getConsoleUtil(); if (consoleUtil.getConsoleIndentation() > 0) { - consoleIndentation.enter(this); - Strings.builderAppend(builder, consoleUtil.getConsoleIndentationString()); + builderProfile.repeat(appendCodePointNode, sb, ' ', consoleUtil.getConsoleIndentation() * 2); } if (argumentsCount.profile(this, arguments.length == 1)) { - Strings.builderAppend(builder, toString1(arguments[0])); + builderProfile.append(appendStringNode, sb, toString1(arguments[0])); } else { for (int i = 0; i < arguments.length; i++) { if (i != 0) { - Strings.builderAppend(builder, ' '); + builderProfile.append(appendCodePointNode, sb, ' '); } - Strings.builderAppend(builder, toString1(arguments[i])); + builderProfile.append(appendStringNode, sb, toString1(arguments[i])); } } - return printIntl(builder); + if (!noNewLine) { + builderProfile.append(appendStringNode, sb, Strings.LINE_SEPARATOR); + } + TruffleString string = StringBuilderProfile.toString(toStringNode, sb); + return printString(string, realm); } @TruffleBoundary - private Object printIntl(TruffleStringBuilderUTF16 builder) { - JSRealm realm = getRealm(); - if (!noNewLine) { - Strings.builderAppend(builder, Strings.LINE_SEPARATOR); - } + private Object printString(TruffleString string, JSRealm realm) { PrintWriter writer = useErr ? realm.getErrorWriter() : realm.getOutputWriter(); - writer.print(Strings.builderToString(builder)); + writer.print(string); writer.flush(); return Undefined.instance; } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/StringBuilderProfile.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/StringBuilderProfile.java index ff162b8f9d0..7194d9a8db0 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/StringBuilderProfile.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/StringBuilderProfile.java @@ -40,6 +40,7 @@ */ package com.oracle.truffle.js.runtime.util; +import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.nodes.NodeCloneable; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -64,6 +65,7 @@ private StringBuilderProfile(int stringLengthLimit) { this.errorBranch = BranchProfile.create(); } + @NeverDefault public static StringBuilderProfile create(int stringLengthLimit) { return new StringBuilderProfile(stringLengthLimit); } @@ -102,6 +104,19 @@ public void append(TruffleStringBuilder.AppendCharUTF16Node node, TruffleStringB Strings.builderAppend(node, builder, c); } + public void append(TruffleStringBuilder.AppendCodePointNode node, TruffleStringBuilderUTF16 builder, int codePoint) { + repeat(node, builder, codePoint, 1); + } + + public void repeat(TruffleStringBuilder.AppendCodePointNode node, TruffleStringBuilderUTF16 builder, int codePoint, int repeat) { + int utf16Length = (codePoint <= Character.MAX_VALUE ? 1 : 2) * repeat; + if (Strings.builderLength(builder) + utf16Length > stringLengthLimit) { + errorBranch.enter(); + throw Errors.createRangeErrorInvalidStringLength(); + } + node.execute(builder, codePoint, repeat); + } + public void append(TruffleStringBuilder.AppendIntNumberNode node, TruffleStringBuilderUTF16 builder, int intValue) { if (Strings.builderLength(builder) + MAX_INT_STRING_LENGTH > stringLengthLimit) { errorBranch.enter(); From 9f099181c1819703e8f643f75e9c1501a0c1a242 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 17 Jul 2024 13:02:09 +0200 Subject: [PATCH 124/265] Remove redundant type check. --- .../src/com/oracle/truffle/js/builtins/AtomicsBuiltins.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/AtomicsBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/AtomicsBuiltins.java index 70f88304e06..7550691cb81 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/AtomicsBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/AtomicsBuiltins.java @@ -219,7 +219,7 @@ public AtomicsOperationNode(JSContext context, JSBuiltin builtin) { } public static boolean isSharedBufferView(JSTypedArrayObject object) { - return JSArrayBufferView.isJSArrayBufferView(object) && JSSharedArrayBuffer.isJSSharedArrayBuffer(JSArrayBufferView.getArrayBuffer(object)); + return JSSharedArrayBuffer.isJSSharedArrayBuffer(JSArrayBufferView.getArrayBuffer(object)); } public static boolean isInt32SharedBufferView(JSTypedArrayObject object) { From b80b756592b4b6b7b78727342146e628e69fad88 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 17 Jul 2024 15:33:13 +0200 Subject: [PATCH 125/265] Improve DataView constructor specializations. --- .../js/builtins/ConstructorBuiltins.java | 34 +++++++++++++------ 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java index ea936731309..558909cb77a 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java @@ -218,6 +218,7 @@ import com.oracle.truffle.js.runtime.builtins.JSBoolean; import com.oracle.truffle.js.runtime.builtins.JSBooleanObject; import com.oracle.truffle.js.runtime.builtins.JSDataView; +import com.oracle.truffle.js.runtime.builtins.JSDataViewObject; import com.oracle.truffle.js.runtime.builtins.JSDate; import com.oracle.truffle.js.runtime.builtins.JSDateObject; import com.oracle.truffle.js.runtime.builtins.JSError; @@ -2496,8 +2497,17 @@ public ConstructDataViewNode(JSContext context, JSBuiltin builtin, boolean isNew super(context, builtin, isNewTargetCase); } - @Specialization(guards = {"isJSHeapArrayBuffer(buffer)"}) - protected final JSDynamicObject ofHeapArrayBuffer(JSDynamicObject newTarget, JSArrayBufferObject buffer, Object byteOffset, Object byteLength, + @Specialization + protected final JSDataViewObject ofHeapArrayBuffer(JSDynamicObject newTarget, JSArrayBufferObject.Heap buffer, Object byteOffset, Object byteLength, + @Cached @Shared InlinedBranchProfile errorBranch, + @Cached @Shared InlinedConditionProfile byteLengthCondition, + @Cached @Shared JSToIndexNode offsetToIndexNode, + @Cached @Shared JSToIndexNode lengthToIndexNode) { + return constructDataView(newTarget, buffer, byteOffset, byteLength, false, errorBranch, byteLengthCondition, offsetToIndexNode, lengthToIndexNode, null); + } + + @Specialization + protected final JSDataViewObject ofDirectArrayBuffer(JSDynamicObject newTarget, JSArrayBufferObject.Direct buffer, Object byteOffset, Object byteLength, @Cached @Shared InlinedBranchProfile errorBranch, @Cached @Shared InlinedConditionProfile byteLengthCondition, @Cached @Shared JSToIndexNode offsetToIndexNode, @@ -2505,8 +2515,8 @@ protected final JSDynamicObject ofHeapArrayBuffer(JSDynamicObject newTarget, JSA return constructDataView(newTarget, buffer, byteOffset, byteLength, false, errorBranch, byteLengthCondition, offsetToIndexNode, lengthToIndexNode, null); } - @Specialization(guards = {"isJSDirectOrSharedArrayBuffer(buffer)"}) - protected final JSDynamicObject ofDirectArrayBuffer(JSDynamicObject newTarget, JSArrayBufferObject buffer, Object byteOffset, Object byteLength, + @Specialization + protected final JSDataViewObject ofSharedArrayBuffer(JSDynamicObject newTarget, JSArrayBufferObject.Shared buffer, Object byteOffset, Object byteLength, @Cached @Shared InlinedBranchProfile errorBranch, @Cached @Shared InlinedConditionProfile byteLengthCondition, @Cached @Shared JSToIndexNode offsetToIndexNode, @@ -2514,8 +2524,8 @@ protected final JSDynamicObject ofDirectArrayBuffer(JSDynamicObject newTarget, J return constructDataView(newTarget, buffer, byteOffset, byteLength, false, errorBranch, byteLengthCondition, offsetToIndexNode, lengthToIndexNode, null); } - @Specialization(guards = {"isJSInteropArrayBuffer(buffer)"}) - protected final JSDynamicObject ofInteropArrayBuffer(JSDynamicObject newTarget, JSArrayBufferObject buffer, Object byteOffset, Object byteLength, + @Specialization + protected final JSDataViewObject ofInteropArrayBuffer(JSDynamicObject newTarget, JSArrayBufferObject.Interop buffer, Object byteOffset, Object byteLength, @Cached @Shared InlinedBranchProfile errorBranch, @Cached @Shared InlinedConditionProfile byteLengthCondition, @Cached @Shared JSToIndexNode offsetToIndexNode, @@ -2525,13 +2535,13 @@ protected final JSDynamicObject ofInteropArrayBuffer(JSDynamicObject newTarget, } @Specialization(guards = {"!isJSAbstractBuffer(buffer)", "bufferInterop.hasBufferElements(buffer)"}) - protected final JSDynamicObject ofInteropBuffer(JSDynamicObject newTarget, Object buffer, Object byteOffset, Object byteLength, + protected final JSDataViewObject ofInteropBuffer(JSDynamicObject newTarget, Object buffer, Object byteOffset, Object byteLength, @Cached @Shared InlinedBranchProfile errorBranch, @Cached @Shared InlinedConditionProfile byteLengthCondition, @Cached @Shared JSToIndexNode offsetToIndexNode, @Cached @Shared JSToIndexNode lengthToIndexNode, @CachedLibrary(limit = "InteropLibraryLimit") @Shared InteropLibrary bufferInterop) { - JSArrayBufferObject arrayBuffer = JSArrayBuffer.createInteropArrayBuffer(getContext(), getRealm(), buffer); + JSArrayBufferObject.Interop arrayBuffer = JSArrayBuffer.createInteropArrayBuffer(getContext(), getRealm(), buffer); return ofInteropArrayBuffer(newTarget, arrayBuffer, byteOffset, byteLength, errorBranch, byteLengthCondition, offsetToIndexNode, lengthToIndexNode, bufferInterop); } @@ -2542,7 +2552,7 @@ protected static JSDynamicObject error(JSDynamicObject newTarget, Object buffer, throw Errors.createTypeError("Not an ArrayBuffer"); } - protected final JSDynamicObject constructDataView(JSDynamicObject newTarget, JSArrayBufferObject arrayBuffer, Object byteOffset, Object byteLength, + protected final JSDataViewObject constructDataView(JSDynamicObject newTarget, JSArrayBufferObject arrayBuffer, Object byteOffset, Object byteLength, boolean isInteropBuffer, InlinedBranchProfile errorBranch, InlinedConditionProfile byteLengthCondition, @@ -2588,7 +2598,11 @@ protected final JSDynamicObject constructDataView(JSDynamicObject newTarget, JSA // GetPrototypeFromConstructor might have detached the ArrayBuffer as a side effect. checkDetachedBuffer(arrayBuffer, errorBranch); - bufferByteLength = arrayBuffer.getByteLength(); + if (isInteropBuffer) { + bufferByteLength = ConstructArrayBufferNode.getBufferSizeSafe(JSArrayBuffer.getInteropBuffer(arrayBuffer), bufferInterop, this, errorBranch); + } else { + bufferByteLength = arrayBuffer.getByteLength(); + } if (offset > bufferByteLength) { errorBranch.enter(this); throw Errors.createRangeError("offset > bufferByteLength"); From 085a506b48d84e195b675b6709c78dac5863f8bc Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 17 Jul 2024 16:01:26 +0200 Subject: [PATCH 126/265] Improve TypedArray constructor specializations. --- .../builtins/JSConstructTypedArrayNode.java | 40 ++++++++++--------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/JSConstructTypedArrayNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/JSConstructTypedArrayNode.java index 4410eddd805..4c21815f5d2 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/JSConstructTypedArrayNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/JSConstructTypedArrayNode.java @@ -182,22 +182,22 @@ private void checkDetachedBuffer(JSArrayBufferObject buffer) { * If length is not explicitly specified, the length of the ArrayBuffer minus the byteOffset * must be a multiple of the element size of the specific type, or an exception is raised. */ - @Specialization(guards = {"!isUndefined(newTarget)", "isJSHeapArrayBuffer(arrayBuffer)"}) - protected JSDynamicObject doArrayBuffer(JSDynamicObject newTarget, JSArrayBufferObject arrayBuffer, Object byteOffset0, Object length0, + @Specialization(guards = {"!isUndefined(newTarget)"}) + protected JSDynamicObject doArrayBuffer(JSDynamicObject newTarget, JSArrayBufferObject.Heap arrayBuffer, Object byteOffset0, Object length0, @Cached @Shared InlinedConditionProfile lengthIsUndefined) { checkDetachedBuffer(arrayBuffer); - return doArrayBufferImpl(arrayBuffer, byteOffset0, length0, newTarget, BUFFER_TYPE_ARRAY, this, lengthIsUndefined); + return doArrayBufferImpl(arrayBuffer, byteOffset0, length0, newTarget, BUFFER_TYPE_ARRAY, this, lengthIsUndefined, null); } - @Specialization(guards = {"!isUndefined(newTarget)", "isJSDirectArrayBuffer(arrayBuffer)"}) - protected JSDynamicObject doDirectArrayBuffer(JSDynamicObject newTarget, JSArrayBufferObject arrayBuffer, Object byteOffset0, Object length0, + @Specialization(guards = {"!isUndefined(newTarget)"}) + protected JSDynamicObject doDirectArrayBuffer(JSDynamicObject newTarget, JSArrayBufferObject.Direct arrayBuffer, Object byteOffset0, Object length0, @Cached @Shared InlinedConditionProfile lengthIsUndefined) { checkDetachedBuffer(arrayBuffer); - return doArrayBufferImpl(arrayBuffer, byteOffset0, length0, newTarget, BUFFER_TYPE_DIRECT, this, lengthIsUndefined); + return doArrayBufferImpl(arrayBuffer, byteOffset0, length0, newTarget, BUFFER_TYPE_DIRECT, this, lengthIsUndefined, null); } private JSDynamicObject doArrayBufferImpl(JSArrayBufferObject arrayBuffer, Object byteOffset0, Object length0, JSDynamicObject newTarget, - byte bufferType, Node node, InlinedConditionProfile lengthIsUndefinedProfile) { + byte bufferType, Node node, InlinedConditionProfile lengthIsUndefinedProfile, InteropLibrary interop) { final int elementSize = factory.getBytesPerElement(); final long byteOffset = toIndex(byteOffset0); @@ -211,7 +211,10 @@ private JSDynamicObject doArrayBufferImpl(JSArrayBufferObject arrayBuffer, Objec checkDetachedBuffer(arrayBuffer); - long bufferByteLength = arrayBuffer.getByteLength(); + assert interop != null == arrayBuffer instanceof JSArrayBufferObject.Interop; + long bufferByteLength = interop == null + ? arrayBuffer.getByteLength() + : ((JSArrayBufferObject.Interop) arrayBuffer).getByteLength(interop); if (lengthIsUndefinedProfile.profile(node, length0 == Undefined.instance)) { if (arrayBuffer.isFixedLength()) { rangeCheckIsMultipleOfElementSize(bufferByteLength % elementSize == 0, "buffer.byteLength", factory.getName(), elementSize); @@ -243,10 +246,10 @@ private JSDynamicObject doArrayBufferImpl(JSArrayBufferObject arrayBuffer, Objec * standard ArrayBuffer, optional parameters (byteOffset and length) can be used to limit the * section of the buffer referenced. */ - @Specialization(guards = {"!isUndefined(newTarget)", "isJSSharedArrayBuffer(arrayBuffer)"}) - protected JSDynamicObject doSharedArrayBuffer(JSDynamicObject newTarget, JSArrayBufferObject arrayBuffer, Object byteOffset0, Object length0, + @Specialization(guards = {"!isUndefined(newTarget)"}) + protected JSDynamicObject doSharedArrayBuffer(JSDynamicObject newTarget, JSArrayBufferObject.Shared arrayBuffer, Object byteOffset0, Object length0, @Cached @Shared InlinedConditionProfile lengthIsUndefined) { - return doArrayBufferImpl(arrayBuffer, byteOffset0, length0, newTarget, BUFFER_TYPE_SHARED, this, lengthIsUndefined); + return doArrayBufferImpl(arrayBuffer, byteOffset0, length0, newTarget, BUFFER_TYPE_SHARED, this, lengthIsUndefined, null); } /** @@ -257,10 +260,11 @@ protected JSDynamicObject doSharedArrayBuffer(JSDynamicObject newTarget, JSArray * standard ArrayBuffer, optional parameters (byteOffset and length) can be used to limit the * section of the buffer referenced. */ - @Specialization(guards = {"!isUndefined(newTarget)", "isJSInteropArrayBuffer(arrayBuffer)"}) - protected JSDynamicObject doInteropArrayBuffer(JSDynamicObject newTarget, JSArrayBufferObject arrayBuffer, Object byteOffset0, Object length0, - @Cached @Shared InlinedConditionProfile lengthIsUndefined) { - return doArrayBufferImpl(arrayBuffer, byteOffset0, length0, newTarget, BUFFER_TYPE_INTEROP, this, lengthIsUndefined); + @Specialization(guards = {"!isUndefined(newTarget)"}) + protected JSDynamicObject doInteropArrayBuffer(JSDynamicObject newTarget, JSArrayBufferObject.Interop arrayBuffer, Object byteOffset0, Object length0, + @Cached @Shared InlinedConditionProfile lengthIsUndefined, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary bufferInterop) { + return doArrayBufferImpl(arrayBuffer, byteOffset0, length0, newTarget, BUFFER_TYPE_INTEROP, this, lengthIsUndefined, bufferInterop); } /** @@ -411,9 +415,9 @@ protected JSDynamicObject doForeignObject(JSDynamicObject newTarget, Object obje @Cached ImportValueNode importValue, @Cached @Exclusive InlinedConditionProfile lengthIsUndefined) { if (interop.hasBufferElements(object)) { - JSArrayBufferObject arrayBuffer = JSArrayBuffer.createInteropArrayBuffer(getContext(), getRealm(), object); - checkLengthLimit(arrayBuffer.getByteLength(), 1); - return doArrayBufferImpl(arrayBuffer, byteOffset0, length0, newTarget, BUFFER_TYPE_INTEROP, node, lengthIsUndefined); + JSArrayBufferObject.Interop arrayBuffer = JSArrayBuffer.createInteropArrayBuffer(getContext(), getRealm(), object); + checkLengthLimit(arrayBuffer.getByteLength(interop), 1); + return doArrayBufferImpl(arrayBuffer, byteOffset0, length0, newTarget, BUFFER_TYPE_INTEROP, node, lengthIsUndefined, interop); } long length; From 61697c1fee1c3bdf2f40f3cad2c182bfd2a3827f Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 23 Jul 2024 19:11:36 +0200 Subject: [PATCH 127/265] Specialize ArrayBuffer.prototype methods for different ArrayBuffer types. --- .../ArrayBufferPrototypeBuiltins.java | 110 +++++++++++------- 1 file changed, 67 insertions(+), 43 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayBufferPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayBufferPrototypeBuiltins.java index c0eebd24773..900479b0bfc 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayBufferPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayBufferPrototypeBuiltins.java @@ -54,14 +54,12 @@ import com.oracle.truffle.api.interop.UnsupportedMessageException; import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.profiles.InlinedBranchProfile; -import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.js.builtins.ArrayBufferPrototypeBuiltinsFactory.ByteLengthGetterNodeGen; import com.oracle.truffle.js.builtins.ArrayBufferPrototypeBuiltinsFactory.DetachedGetterNodeGen; -import com.oracle.truffle.js.builtins.ArrayBufferPrototypeBuiltinsFactory.MaxByteLengthGetterNodeGen; -import com.oracle.truffle.js.builtins.ArrayBufferPrototypeBuiltinsFactory.ResizableGetterNodeGen; import com.oracle.truffle.js.builtins.ArrayBufferPrototypeBuiltinsFactory.JSArrayBufferResizeNodeGen; import com.oracle.truffle.js.builtins.ArrayBufferPrototypeBuiltinsFactory.JSArrayBufferSliceNodeGen; import com.oracle.truffle.js.builtins.ArrayBufferPrototypeBuiltinsFactory.JSArrayBufferTransferNodeGen; +import com.oracle.truffle.js.builtins.ArrayBufferPrototypeBuiltinsFactory.ResizableGetterNodeGen; import com.oracle.truffle.js.builtins.ArrayPrototypeBuiltins.ArraySpeciesConstructorNode; import com.oracle.truffle.js.nodes.cast.JSToIndexNode; import com.oracle.truffle.js.nodes.cast.JSToIntegerAsLongNode; @@ -136,15 +134,14 @@ protected Object createNode(JSContext context, JSBuiltin builtin, boolean constr case slice: return JSArrayBufferSliceNodeGen.create(context, builtin, args().withThis().fixedArgs(2).createArgumentNodes(context)); case byteLength: - return ByteLengthGetterNodeGen.create(context, builtin, args().withThis().createArgumentNodes(context)); + case maxByteLength: + return ByteLengthGetterNodeGen.create(context, builtin, builtinEnum == ArrayBufferPrototype.maxByteLength, args().withThis().createArgumentNodes(context)); case detached: return DetachedGetterNodeGen.create(context, builtin, args().withThis().createArgumentNodes(context)); case transfer: return JSArrayBufferTransferNodeGen.create(context, builtin, true, args().withThis().fixedArgs(1).createArgumentNodes(context)); case transferToFixedLength: return JSArrayBufferTransferNodeGen.create(context, builtin, false, args().withThis().fixedArgs(1).createArgumentNodes(context)); - case maxByteLength: - return MaxByteLengthGetterNodeGen.create(context, builtin, args().withThis().createArgumentNodes(context)); case resizable: return ResizableGetterNodeGen.create(context, builtin, args().withThis().createArgumentNodes(context)); case resize: @@ -156,8 +153,11 @@ protected Object createNode(JSContext context, JSBuiltin builtin, boolean constr @ImportStatic({JSArrayBuffer.class, JSConfig.class}) public abstract static class ByteLengthGetterNode extends JSBuiltinNode { - public ByteLengthGetterNode(JSContext context, JSBuiltin builtin) { + private final boolean getMaxByteLength; + + public ByteLengthGetterNode(JSContext context, JSBuiltin builtin, boolean getMaxByteLength) { super(context, builtin); + this.getMaxByteLength = getMaxByteLength; } @Specialization @@ -165,6 +165,9 @@ protected int heapArrayBuffer(JSArrayBufferObject.Heap thisObj) { if (!getContext().getTypedArrayNotDetachedAssumption().isValid() && thisObj.getByteArray() == null) { return 0; } + if (getMaxByteLength && !thisObj.isFixedLength()) { + return thisObj.getMaxByteLength(); + } return thisObj.getByteLength(); } @@ -173,6 +176,9 @@ protected int directArrayBuffer(JSArrayBufferObject.Direct thisObj) { if (!getContext().getTypedArrayNotDetachedAssumption().isValid() && thisObj.getByteBuffer() == null) { return 0; } + if (getMaxByteLength && !thisObj.isFixedLength()) { + return thisObj.getMaxByteLength(); + } return thisObj.getByteLength(); } @@ -183,6 +189,9 @@ protected int interopArrayBuffer(JSArrayBufferObject.Interop thisObj, if (!getContext().getTypedArrayNotDetachedAssumption().isValid() && buffer == null) { return 0; } + if (getMaxByteLength && !thisObj.isFixedLength()) { + return thisObj.getMaxByteLength(); + } try { long bufferSize = interop.getBufferSize(buffer); // Buffer size was already checked in the ArrayBuffer constructor. @@ -459,12 +468,30 @@ public JSArrayBufferTransferNode(JSContext context, JSBuiltin builtin, boolean p this.preserveResizability = preserveResizability; } - @Specialization(guards = {"!isJSSharedArrayBuffer(arrayBuffer)"}) - protected Object transfer(JSArrayBufferObject arrayBuffer, Object newLength, - @Cached JSToIndexNode toIndexNode, - @Cached InlinedBranchProfile errorBranch, - @Cached InlinedConditionProfile heapBufferProfile, - @Cached InlinedConditionProfile directBufferProfile) { + @Specialization + protected final Object arrayBufferHeap(JSArrayBufferObject.Heap thisObj, Object newLength, + @Cached @Shared JSToIndexNode toIndexNode, + @Cached @Shared InlinedBranchProfile errorBranch) { + return transfer(thisObj, newLength, toIndexNode, errorBranch); + } + + @Specialization + protected final Object arrayBufferDirect(JSArrayBufferObject.Direct thisObj, Object newLength, + @Cached @Shared JSToIndexNode toIndexNode, + @Cached @Shared InlinedBranchProfile errorBranch) { + return transfer(thisObj, newLength, toIndexNode, errorBranch); + } + + @Specialization + protected final Object arrayBufferInterop(JSArrayBufferObject.Interop thisObj, Object newLength, + @Cached @Shared JSToIndexNode toIndexNode, + @Cached @Shared InlinedBranchProfile errorBranch) { + return transfer(thisObj, newLength, toIndexNode, errorBranch); + } + + private Object transfer(JSArrayBufferObject arrayBuffer, Object newLength, + JSToIndexNode toIndexNode, + InlinedBranchProfile errorBranch) { int newByteLength; int oldByteLength = arrayBuffer.getByteLength(); if (newLength == Undefined.instance) { @@ -505,8 +532,7 @@ protected Object transfer(JSArrayBufferObject arrayBuffer, Object newLength, JSRealm realm = getRealm(); JSArrayBufferObject newBuffer; - if (heapBufferProfile.profile(this, JSArrayBuffer.isJSHeapArrayBuffer(arrayBuffer))) { - JSArrayBufferObject.Heap heapArrayBuffer = (JSArrayBufferObject.Heap) arrayBuffer; + if (arrayBuffer instanceof JSArrayBufferObject.Heap heapArrayBuffer) { byte[] array = heapArrayBuffer.getByteArray(); if (oldByteLength < newByteLength) { if (newByteLength <= array.length) { @@ -518,8 +544,7 @@ protected Object transfer(JSArrayBufferObject arrayBuffer, Object newLength, } } newBuffer = JSArrayBuffer.createArrayBuffer(context, realm, array, newByteLength, newMaxByteLength); - } else if (directBufferProfile.profile(this, JSArrayBuffer.isJSDirectArrayBuffer(arrayBuffer))) { - JSArrayBufferObject.Direct directArrayBuffer = (JSArrayBufferObject.Direct) arrayBuffer; + } else if (arrayBuffer instanceof JSArrayBufferObject.Direct directArrayBuffer) { ByteBuffer byteBuffer = directArrayBuffer.getByteBuffer(); if (oldByteLength < newByteLength) { if (newByteLength <= byteBuffer.capacity()) { @@ -550,27 +575,6 @@ protected static Object error(@SuppressWarnings("unused") Object thisObj, @Suppr } - public abstract static class MaxByteLengthGetterNode extends JSBuiltinNode { - - public MaxByteLengthGetterNode(JSContext context, JSBuiltin builtin) { - super(context, builtin); - } - - @Specialization(guards = {"!isJSSharedArrayBuffer(thisObj)"}) - protected int arrayBuffer(JSArrayBufferObject thisObj) { - if (!getContext().getTypedArrayNotDetachedAssumption().isValid() && thisObj.isDetached()) { - return 0; - } - return thisObj.isFixedLength() ? thisObj.getByteLength() : thisObj.getMaxByteLength(); - } - - @Fallback - protected static int error(@SuppressWarnings("unused") Object thisObj) { - throw Errors.createTypeErrorArrayBufferExpected(); - } - - } - public abstract static class ResizableGetterNode extends JSBuiltinNode { public ResizableGetterNode(JSContext context, JSBuiltin builtin) { @@ -595,10 +599,30 @@ public JSArrayBufferResizeNode(JSContext context, JSBuiltin builtin) { super(context, builtin); } - @Specialization(guards = {"!isJSSharedArrayBuffer(thisObj)"}) - protected Object arrayBuffer(JSArrayBufferObject thisObj, Object newLength, - @Cached JSToIndexNode toIndexNode, - @Cached InlinedBranchProfile errorBranch) { + @Specialization + protected final Object arrayBufferHeap(JSArrayBufferObject.Heap thisObj, Object newLength, + @Cached @Shared JSToIndexNode toIndexNode, + @Cached @Shared InlinedBranchProfile errorBranch) { + return arrayBuffer(thisObj, newLength, toIndexNode, errorBranch); + } + + @Specialization + protected final Object arrayBufferDirect(JSArrayBufferObject.Direct thisObj, Object newLength, + @Cached @Shared JSToIndexNode toIndexNode, + @Cached @Shared InlinedBranchProfile errorBranch) { + return arrayBuffer(thisObj, newLength, toIndexNode, errorBranch); + } + + @Specialization + protected final Object arrayBufferInterop(JSArrayBufferObject.Interop thisObj, Object newLength, + @Cached @Shared JSToIndexNode toIndexNode, + @Cached @Shared InlinedBranchProfile errorBranch) { + return arrayBuffer(thisObj, newLength, toIndexNode, errorBranch); + } + + private Object arrayBuffer(JSArrayBufferObject thisObj, Object newLength, + JSToIndexNode toIndexNode, + InlinedBranchProfile errorBranch) { if (thisObj.isFixedLength()) { errorBranch.enter(this); throw Errors.createTypeError("Resizable ArrayBuffer expected!"); @@ -619,7 +643,7 @@ protected Object arrayBuffer(JSArrayBufferObject thisObj, Object newLength, } int oldByteLength = thisObj.getByteLength(); if (newByteLength < oldByteLength) { - getJSContext().getArrayBufferNotShrunkAssumption().invalidate("ArrayBuffer shrunk"); + getContext().getArrayBufferNotShrunkAssumption().invalidate("ArrayBuffer shrunk"); // Clear unused elements on shrink (so that we don't have to // do that on the subsequent grow). We don't do that on grow // because it is not needed unless a shrink happens before From 4ef100340fc67824ededddd8da5794c49505415f Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 23 Jul 2024 19:32:44 +0200 Subject: [PATCH 128/265] Narrow return type of ArrayBuffer.prototype.slice specializations. --- .../js/builtins/ArrayBufferPrototypeBuiltins.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayBufferPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayBufferPrototypeBuiltins.java index 900479b0bfc..736449fe1d8 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayBufferPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayBufferPrototypeBuiltins.java @@ -303,7 +303,7 @@ public JSArrayBufferSliceNode(JSContext context, JSBuiltin builtin) { * @return sliced ArrayBuffer */ @Specialization - protected JSDynamicObject sliceIntInt(JSArrayBufferObject.Heap thisObj, int begin, int end, + protected JSArrayBufferObject sliceIntInt(JSArrayBufferObject.Heap thisObj, int begin, int end, @Cached @Shared InlinedBranchProfile errorBranch) { checkDetachedBuffer(thisObj, errorBranch); int byteLength = thisObj.getByteLength(); @@ -351,7 +351,7 @@ private void checkDetachedBuffer(JSArrayBufferObject arrayBuffer, InlinedBranchP } @Specialization(replaces = "sliceIntInt") - protected JSDynamicObject slice(JSArrayBufferObject.Heap thisObj, Object begin0, Object end0, + protected JSArrayBufferObject slice(JSArrayBufferObject.Heap thisObj, Object begin0, Object end0, @Cached @Shared InlinedBranchProfile errorBranch) { checkDetachedBuffer(thisObj, errorBranch); int len = thisObj.getByteLength(); @@ -361,7 +361,7 @@ protected JSDynamicObject slice(JSArrayBufferObject.Heap thisObj, Object begin0, } @Specialization - protected JSDynamicObject sliceDirectIntInt(JSArrayBufferObject.Direct thisObj, int begin, int end, + protected JSArrayBufferObject sliceDirectIntInt(JSArrayBufferObject.Direct thisObj, int begin, int end, @Cached @Shared InlinedBranchProfile errorBranch) { checkDetachedBuffer(thisObj, errorBranch); ByteBuffer byteBuffer = JSArrayBuffer.getDirectByteBuffer(thisObj); @@ -378,7 +378,7 @@ protected JSDynamicObject sliceDirectIntInt(JSArrayBufferObject.Direct thisObj, } @Specialization(replaces = "sliceDirectIntInt") - protected JSDynamicObject sliceDirect(JSArrayBufferObject.Direct thisObj, Object begin0, Object end0, + protected JSArrayBufferObject sliceDirect(JSArrayBufferObject.Direct thisObj, Object begin0, Object end0, @Cached @Shared InlinedBranchProfile errorBranch) { checkDetachedBuffer(thisObj, errorBranch); int len = thisObj.getByteLength(); @@ -388,7 +388,7 @@ protected JSDynamicObject sliceDirect(JSArrayBufferObject.Direct thisObj, Object } @Specialization - protected Object sliceInterop(JSArrayBufferObject.Interop thisObj, Object begin0, Object end0, + protected JSArrayBufferObject sliceInterop(JSArrayBufferObject.Interop thisObj, Object begin0, Object end0, @Cached @Shared InlinedBranchProfile errorBranch, @CachedLibrary(limit = "InteropLibraryLimit") @Shared InteropLibrary srcBufferLib, @CachedLibrary(limit = "InteropLibraryLimit") @Shared InteropLibrary dstBufferLib) { @@ -420,7 +420,7 @@ private void copyInteropBufferElements(Object srcBuffer, Object dstBuffer, int s } @Specialization(guards = {"!isJSSharedArrayBuffer(thisObj)", "hasBufferElements(thisObj, srcBufferLib)"}) - protected Object sliceTruffleBuffer(Object thisObj, Object begin0, Object end0, + protected JSArrayBufferObject sliceTruffleBuffer(Object thisObj, Object begin0, Object end0, @Cached @Shared InlinedBranchProfile errorBranch, @CachedLibrary(limit = "InteropLibraryLimit") @Shared InteropLibrary srcBufferLib, @CachedLibrary(limit = "InteropLibraryLimit") @Shared InteropLibrary dstBufferLib) { @@ -429,7 +429,7 @@ protected Object sliceTruffleBuffer(Object thisObj, Object begin0, Object end0, } @Fallback - protected static JSDynamicObject error(Object thisObj, @SuppressWarnings("unused") Object begin0, @SuppressWarnings("unused") Object end0) { + protected static JSArrayBufferObject error(Object thisObj, @SuppressWarnings("unused") Object begin0, @SuppressWarnings("unused") Object end0) { throw Errors.createTypeErrorIncompatibleReceiver(thisObj); } From 1a5cceb16acb9e0c0de0fb918e05e8da540c190d Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Mon, 29 Jul 2024 23:54:13 +0200 Subject: [PATCH 129/265] Do not use SimpleFormatter in Intl.ListFormat.prototype.formatToParts(). --- .../runtime/builtins/intl/JSListFormat.java | 40 +++++++++---------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/intl/JSListFormat.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/intl/JSListFormat.java index 4c417d6ffac..a83cb7ad044 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/intl/JSListFormat.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/intl/JSListFormat.java @@ -40,13 +40,14 @@ */ package com.oracle.truffle.js.runtime.builtins.intl; +import java.text.Format; import java.util.ArrayList; import java.util.List; import java.util.Locale; import org.graalvm.shadowed.com.ibm.icu.impl.ICUResourceBundle; +import org.graalvm.shadowed.com.ibm.icu.text.ConstrainedFieldPosition; import org.graalvm.shadowed.com.ibm.icu.text.ListFormatter; -import org.graalvm.shadowed.com.ibm.icu.text.SimpleFormatter; import org.graalvm.shadowed.com.ibm.icu.util.ULocale; import org.graalvm.shadowed.com.ibm.icu.util.UResourceBundle; @@ -190,33 +191,28 @@ public static TruffleString format(JSListFormatObject listFormatObj, List list) { - if (list.size() == 0) { + if (list.isEmpty()) { return JSArray.createConstantEmptyArray(context, realm); } ListFormatter listFormatter = getListFormatterProperty(listFormatObj); - String pattern = listFormatter.getPatternForNumItems(list.size()); - int[] offsets = new int[list.size()]; - SimpleFormatter simpleFormatter = SimpleFormatter.compile(pattern); - StringBuilder formatted = new StringBuilder(); - simpleFormatter.formatAndAppend(formatted, offsets, list.toArray(new String[]{})); - int i = 0; - int idx = 0; + ListFormatter.FormattedList formattedList = listFormatter.formatToValue(list); List resultParts = new ArrayList<>(); - for (String element : list) { - int nextOffset = offsets[idx++]; - if (i < nextOffset) { // literal - resultParts.add(IntlUtil.makePart(context, realm, IntlUtil.LITERAL, formatted.substring(i, nextOffset))); - i = nextOffset; - } - if (i == nextOffset) { // element - int elemLength = element.length(); - resultParts.add(IntlUtil.makePart(context, realm, IntlUtil.ELEMENT, formatted.substring(i, i + elemLength))); - i += elemLength; + + ConstrainedFieldPosition cfPos = new ConstrainedFieldPosition(); + while (formattedList.nextPosition(cfPos)) { + Format.Field field = cfPos.getField(); + String type; + if (field == ListFormatter.Field.LITERAL) { + type = IntlUtil.LITERAL; + } else if (field == ListFormatter.Field.ELEMENT) { + type = IntlUtil.ELEMENT; + } else { + continue; } + String value = formattedList.subSequence(cfPos.getStart(), cfPos.getLimit()).toString(); + resultParts.add(IntlUtil.makePart(context, realm, type, value)); } - if (i < formatted.length()) { - resultParts.add(IntlUtil.makePart(context, realm, IntlUtil.LITERAL, formatted.substring(i, formatted.length()))); - } + return JSArray.createConstant(context, realm, resultParts.toArray()); } From af4b09180bc909572cc357a9e4233af6ce7367df Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Mon, 29 Jul 2024 23:56:51 +0200 Subject: [PATCH 130/265] Regression test of the handling of longer lists by Intl.ListFormat.prototype.formatToParts. --- .../com.oracle.truffle.js.test/js/GR-56527.js | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 graal-js/src/com.oracle.truffle.js.test/js/GR-56527.js diff --git a/graal-js/src/com.oracle.truffle.js.test/js/GR-56527.js b/graal-js/src/com.oracle.truffle.js.test/js/GR-56527.js new file mode 100644 index 00000000000..3a1486ee05a --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/js/GR-56527.js @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ + +/** + * Regression test of the handling of longer lists by Intl.ListFormat. + */ + +load("assert.js"); + +const length = 300; +const result = new Intl.ListFormat('en').formatToParts(new Array(300).fill('x')); +assertSame(2*length-1, result.length); +for (let i = 0; i < result.length; i++) { + const part = result[i]; + if (i%2 === 0) { + assertSame('element', part.type); + assertSame('x', part.value); + } else { + assertSame('literal', part.type); + const expectedLiteral = (i === result.length - 2) ? ', and ' : ', '; + assertSame(expectedLiteral, part.value); + } +} + +// Original test-case from the fuzzer, +// just make sure that we do not throw an internal error + +const v2 = "{3991}, {3992}, {3993}, {3994}, {3995}, {3996}, {3997}, {3998}, {3999}, {4000}, {4001}, {4002}, {4003}, {4004}, {4005}, {4006}, {4007}, {4008}, {4009}, {4010}, {4011}, {4012}, {4013}, {4014}, {4015}, {4016}, {4017}, {4018}, {4019}, {4020}, {4021}, and {4022}"; +const v7 = new Intl.ListFormat(); +v7.formatToParts(v2); \ No newline at end of file From d07f5dc32e63a3e58400ae299ca5e90c5eaacc2f Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 29 Jul 2024 17:42:18 +0200 Subject: [PATCH 131/265] Change ScriptArray.hasHoles() to only return true for holes between first and last index. --- .../js/builtins/ArrayPrototypeBuiltins.java | 10 +++++----- .../array/JSArrayToDenseObjectArrayNode.java | 3 ++- .../truffle/js/nodes/array/TestArrayNode.java | 10 +++++++++- .../truffle/js/runtime/array/ScriptArray.java | 17 ++++++++++++++++- .../dyn/AbstractContiguousDoubleArray.java | 8 +------- .../array/dyn/AbstractContiguousIntArray.java | 8 +------- .../dyn/AbstractContiguousJSObjectArray.java | 8 +------- .../dyn/AbstractContiguousObjectArray.java | 8 +------- .../array/dyn/AbstractWritableArray.java | 13 +++++++++++++ .../js/runtime/array/dyn/HolesDoubleArray.java | 7 ++++++- .../js/runtime/array/dyn/HolesIntArray.java | 7 ++++++- .../runtime/array/dyn/HolesJSObjectArray.java | 7 ++++++- .../js/runtime/array/dyn/HolesObjectArray.java | 7 ++++++- .../runtime/array/dyn/ZeroBasedDoubleArray.java | 9 +-------- .../js/runtime/array/dyn/ZeroBasedIntArray.java | 9 +-------- .../array/dyn/ZeroBasedJSObjectArray.java | 9 +-------- .../runtime/array/dyn/ZeroBasedObjectArray.java | 9 +-------- 17 files changed, 77 insertions(+), 72 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java index 49b0e2b07fd..e830bcf6d36 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java @@ -1053,7 +1053,7 @@ protected static boolean isArrayWithoutHolesAndNotSealed(JSDynamicObject thisObj @Specialization(guards = {"isArrayWithoutHolesAndNotSealed(thisObj, isArrayNode, hasHolesNode, isSealedNode)"}) protected Object shiftWithoutHoles(JSDynamicObject thisObj, @Shared @Cached("createIsArray()") @SuppressWarnings("unused") IsArrayNode isArrayNode, - @Shared @Cached("createHasHoles()") @SuppressWarnings("unused") TestArrayNode hasHolesNode, + @Shared @Cached("createHasHolesOrUnused()") @SuppressWarnings("unused") TestArrayNode hasHolesNode, @Shared @Cached("createIsSealed()") @SuppressWarnings("unused") TestArrayNode isSealedNode, @Cached InlinedExactClassProfile arrayTypeProfile, @Shared @Cached InlinedConditionProfile lengthIsZero, @@ -1082,7 +1082,7 @@ protected static boolean isArrayWithHolesOrSealed(JSDynamicObject thisObj, IsArr @Specialization(guards = {"isArrayWithHolesOrSealed(thisObj, isArrayNode, hasHolesNode, isSealedNode)"}) protected Object shiftWithHoles(JSDynamicObject thisObj, @Shared @Cached("createIsArray()") @SuppressWarnings("unused") IsArrayNode isArrayNode, - @Shared @Cached("createHasHoles()") @SuppressWarnings("unused") TestArrayNode hasHolesNode, + @Shared @Cached("createHasHolesOrUnused()") @SuppressWarnings("unused") TestArrayNode hasHolesNode, @Shared @Cached("createIsSealed()") @SuppressWarnings("unused") TestArrayNode isSealedNode, @Shared @Cached("create(THROW_ERROR)") DeletePropertyNode deletePropertyNode, @Shared @Cached InlinedConditionProfile lengthIsZero) { @@ -1193,7 +1193,7 @@ public JSArrayUnshiftNode(JSContext context, JSBuiltin builtin) { } @Child protected IsArrayNode isArrayNode = IsArrayNode.createIsArray(); - @Child protected TestArrayNode hasHolesNode = TestArrayNode.createHasHoles(); + @Child protected TestArrayNode hasHolesNode = TestArrayNode.createHasHolesOrUnused(); protected boolean isFastPath(Object thisObj) { boolean isArray = isArrayNode.execute(thisObj); @@ -3159,7 +3159,7 @@ private boolean deleteProperty(Object array, long index) { @Specialization protected final Object reverseJSArray(JSArrayObject thisObj, - @Shared @Cached("createHasHoles()") TestArrayNode hasHolesNode, + @Shared @Cached("createHasHolesOrUnused()") TestArrayNode hasHolesNode, @Shared @Cached InlinedConditionProfile bothExistProfile, @Shared @Cached InlinedConditionProfile onlyUpperExistsProfile, @Shared @Cached InlinedConditionProfile onlyLowerExistsProfile) { @@ -3169,7 +3169,7 @@ protected final Object reverseJSArray(JSArrayObject thisObj, @Specialization(replaces = "reverseJSArray") protected final Object reverseGeneric(Object thisObj, - @Shared @Cached("createHasHoles()") TestArrayNode hasHolesNode, + @Shared @Cached("createHasHolesOrUnused()") TestArrayNode hasHolesNode, @Shared @Cached InlinedConditionProfile bothExistProfile, @Shared @Cached InlinedConditionProfile onlyUpperExistsProfile, @Shared @Cached InlinedConditionProfile onlyLowerExistsProfile) { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/JSArrayToDenseObjectArrayNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/JSArrayToDenseObjectArrayNode.java index 689f7675b8e..26f4f7bd5a8 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/JSArrayToDenseObjectArrayNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/JSArrayToDenseObjectArrayNode.java @@ -55,7 +55,8 @@ /** * Converts a JS array to an Object[]. If the array is sparse or has holes, it is compacted to a - * dense array that consists of only actual elements. + * dense array that consists of only actual elements. Note that this node assumes that the array has + * only fast own elements and no prototype elements. * * Used by {@code Array.prototype.sort}. */ diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/TestArrayNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/TestArrayNode.java index 16a0ed0e1c2..4ae5f391ab9 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/TestArrayNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/TestArrayNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -53,6 +53,7 @@ public abstract class TestArrayNode extends JavaScriptBaseNode { protected enum Test { HasHoles, + HasHolesOrUnused, IsSealed, } @@ -77,6 +78,11 @@ public static TestArrayNode createHasHoles() { return create(Test.HasHoles); } + @NeverDefault + public static TestArrayNode createHasHolesOrUnused() { + return create(Test.HasHolesOrUnused); + } + @NeverDefault public static TestArrayNode createIsSealed() { return create(Test.IsSealed); @@ -89,6 +95,8 @@ protected final boolean doCached(JSDynamicObject target, @Cached("getArrayType(target)") ScriptArray arrayType) { if (test == Test.HasHoles) { return arrayType.hasHoles(target); + } else if (test == Test.HasHolesOrUnused) { + return arrayType.hasHolesOrUnused(target); } else if (test == Test.IsSealed) { return arrayType.isSealed(); } else { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/ScriptArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/ScriptArray.java index f56053a8515..98dab01ac57 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/ScriptArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/ScriptArray.java @@ -414,7 +414,7 @@ protected static final void traceWrite(String access, long index, Object value) } /** - * Returns true when the this array could have hole values in it. Doesn't tell whether it + * Returns true if this array type could have hole values in it. Doesn't tell whether it * actually HAS holes. */ @Idempotent @@ -422,8 +422,23 @@ public boolean isHolesType() { return false; } + /** + * Returns true when this array actually has holes between {@link #firstElementIndex} and + * {@link #lastElementIndex}. Implies {@link #isHolesType()}. + * + * @see #hasHolesOrUnused + */ public abstract boolean hasHoles(JSDynamicObject object); + /** + * Returns true when this array has any hole or unused elements between 0 and {@link #length}. + * + * @see #hasHoles + */ + public boolean hasHolesOrUnused(JSDynamicObject object) { + return hasHoles(object); + } + /** * This function deletes all elements in the range from [start..end[. This is equivalent to * shifting the whole array, starting with element index end, by end-start positions to the diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractContiguousDoubleArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractContiguousDoubleArray.java index 6cbf8b63f22..79f3fd0dac9 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractContiguousDoubleArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractContiguousDoubleArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,7 +41,6 @@ package com.oracle.truffle.js.runtime.array.dyn; import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arrayGetArrayOffset; -import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arrayGetHoleCount; import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arrayGetIndexOffset; import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arraySetArrayOffset; import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arraySetIndexOffset; @@ -110,11 +109,6 @@ public final long lastElementIndex(JSDynamicObject object) { return getIndexOffset(object) + getArrayOffset(object) + getUsedLength(object) - 1; } - @Override - public boolean hasHoles(JSDynamicObject object) { - return arrayGetHoleCount(object) > 0; - } - @Override public ScriptArray addRangeImpl(JSDynamicObject object, long offset, int size) { return addRangeImplContiguous(object, offset, size); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractContiguousIntArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractContiguousIntArray.java index 6f7158e0b21..2900f12f3f5 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractContiguousIntArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractContiguousIntArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,7 +41,6 @@ package com.oracle.truffle.js.runtime.array.dyn; import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arrayGetArrayOffset; -import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arrayGetHoleCount; import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arrayGetIndexOffset; import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arraySetArrayOffset; import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arraySetIndexOffset; @@ -110,11 +109,6 @@ public final long lastElementIndex(JSDynamicObject object) { return getIndexOffset(object) + getArrayOffset(object) + getUsedLength(object) - 1; } - @Override - public boolean hasHoles(JSDynamicObject object) { - return arrayGetHoleCount(object) > 0; - } - @Override public ScriptArray addRangeImpl(JSDynamicObject object, long offset, int size) { return addRangeImplContiguous(object, offset, size); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractContiguousJSObjectArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractContiguousJSObjectArray.java index c7b7ade3e3e..cc13b6f6589 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractContiguousJSObjectArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractContiguousJSObjectArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,7 +41,6 @@ package com.oracle.truffle.js.runtime.array.dyn; import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arrayGetArrayOffset; -import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arrayGetHoleCount; import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arrayGetIndexOffset; import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arraySetArrayOffset; import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arraySetIndexOffset; @@ -110,11 +109,6 @@ public final long lastElementIndex(JSDynamicObject object) { return getIndexOffset(object) + getArrayOffset(object) + getUsedLength(object) - 1; } - @Override - public boolean hasHoles(JSDynamicObject object) { - return arrayGetHoleCount(object) > 0; - } - @Override public ScriptArray addRangeImpl(JSDynamicObject object, long offset, int size) { return addRangeImplContiguous(object, offset, size); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractContiguousObjectArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractContiguousObjectArray.java index ddf0c806922..6f2c94b1cce 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractContiguousObjectArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractContiguousObjectArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,7 +41,6 @@ package com.oracle.truffle.js.runtime.array.dyn; import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arrayGetArrayOffset; -import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arrayGetHoleCount; import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arrayGetIndexOffset; import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arraySetArrayOffset; import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arraySetIndexOffset; @@ -110,11 +109,6 @@ public final long lastElementIndex(JSDynamicObject object) { return getIndexOffset(object) + getArrayOffset(object) + getUsedLength(object) - 1; } - @Override - public boolean hasHoles(JSDynamicObject object) { - return arrayGetHoleCount(object) > 0; - } - @Override public ScriptArray addRangeImpl(JSDynamicObject object, long offset, int size) { return addRangeImplContiguous(object, offset, size); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractWritableArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractWritableArray.java index 6bb607877b8..a2acd5a57bc 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractWritableArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractWritableArray.java @@ -828,6 +828,19 @@ protected final ScriptArray removeRangeHoles(JSDynamicObject object, long start, return this; } + @Override + public boolean hasHoles(JSDynamicObject object) { + assert arrayGetHoleCount(object) == 0 : arrayGetHoleCount(object); + return false; + } + + @Override + public boolean hasHolesOrUnused(JSDynamicObject object) { + int length = lengthInt(object); + int usedLength = getUsedLength(object); + return usedLength < length || hasHoles(object); + } + protected final int countHoles(JSDynamicObject object) { assert isHolesType(); int arrayOffset = getArrayOffset(object); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/HolesDoubleArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/HolesDoubleArray.java index 7f14c77920a..f63aeaa1439 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/HolesDoubleArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/HolesDoubleArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -213,6 +213,11 @@ public boolean isHolesType() { return true; } + @Override + public boolean hasHoles(JSDynamicObject object) { + return arrayGetHoleCount(object) > 0; + } + @Override public ScriptArray removeRangeImpl(JSDynamicObject object, long start, long end) { return removeRangeHoles(object, start, end); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/HolesIntArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/HolesIntArray.java index cb99483a863..18bbcc63550 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/HolesIntArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/HolesIntArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -234,6 +234,11 @@ public boolean isHolesType() { return true; } + @Override + public boolean hasHoles(JSDynamicObject object) { + return arrayGetHoleCount(object) > 0; + } + @Override public ScriptArray removeRangeImpl(JSDynamicObject object, long start, long end) { return removeRangeHoles(object, start, end); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/HolesJSObjectArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/HolesJSObjectArray.java index f16b39a7301..faf8b08c1b5 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/HolesJSObjectArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/HolesJSObjectArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -212,6 +212,11 @@ public boolean isHolesType() { return true; } + @Override + public boolean hasHoles(JSDynamicObject object) { + return arrayGetHoleCount(object) > 0; + } + @Override public ScriptArray removeRangeImpl(JSDynamicObject object, long start, long end) { return removeRangeHoles(object, start, end); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/HolesObjectArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/HolesObjectArray.java index 4592a06a6e6..9c3858c0cc2 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/HolesObjectArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/HolesObjectArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -194,6 +194,11 @@ public boolean isHolesType() { return true; } + @Override + public boolean hasHoles(JSDynamicObject object) { + return arrayGetHoleCount(object) > 0; + } + @Override public ScriptArray removeRangeImpl(JSDynamicObject object, long start, long end) { return removeRangeHoles(object, start, end); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/ZeroBasedDoubleArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/ZeroBasedDoubleArray.java index 182803c514e..3777943d3ed 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/ZeroBasedDoubleArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/ZeroBasedDoubleArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -186,13 +186,6 @@ public ScriptArray addRangeImpl(JSDynamicObject object, long offset, int size) { return addRangeImplZeroBased(object, offset, size); } - @Override - public boolean hasHoles(JSDynamicObject object) { - int length = lengthInt(object); - int usedLength = getUsedLength(object); - return usedLength < length; - } - @Override protected ZeroBasedDoubleArray withIntegrityLevel(int newIntegrityLevel) { return new ZeroBasedDoubleArray(newIntegrityLevel, cache); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/ZeroBasedIntArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/ZeroBasedIntArray.java index 2547f5b1b72..ddec36a36cd 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/ZeroBasedIntArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/ZeroBasedIntArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -216,13 +216,6 @@ public ScriptArray addRangeImpl(JSDynamicObject object, long offset, int size) { return addRangeImplZeroBased(object, offset, size); } - @Override - public boolean hasHoles(JSDynamicObject object) { - int length = lengthInt(object); - int usedLength = getUsedLength(object); - return usedLength < length; - } - @Override protected ZeroBasedIntArray withIntegrityLevel(int newIntegrityLevel) { return new ZeroBasedIntArray(newIntegrityLevel, cache); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/ZeroBasedJSObjectArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/ZeroBasedJSObjectArray.java index 75481a47f07..1b374955f5a 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/ZeroBasedJSObjectArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/ZeroBasedJSObjectArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -191,13 +191,6 @@ public ScriptArray addRangeImpl(JSDynamicObject object, long offset, int size) { return addRangeImplZeroBased(object, offset, size); } - @Override - public boolean hasHoles(JSDynamicObject object) { - int length = lengthInt(object); - int usedLength = getUsedLength(object); - return usedLength < length; - } - @Override protected ZeroBasedJSObjectArray withIntegrityLevel(int newIntegrityLevel) { return new ZeroBasedJSObjectArray(newIntegrityLevel, cache); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/ZeroBasedObjectArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/ZeroBasedObjectArray.java index 604ea749d54..83a227d3708 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/ZeroBasedObjectArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/ZeroBasedObjectArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -180,13 +180,6 @@ public ScriptArray addRangeImpl(JSDynamicObject object, long offset, int size) { return addRangeImplZeroBased(object, offset, size); } - @Override - public boolean hasHoles(JSDynamicObject object) { - int length = lengthInt(object); - int usedLength = getUsedLength(object); - return usedLength < length; - } - @Override protected ZeroBasedObjectArray withIntegrityLevel(int newIntegrityLevel) { return new ZeroBasedObjectArray(newIntegrityLevel, cache); From ba13aeb70ab9342ff32e9fe7db7366465c76fea9 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 29 Jul 2024 15:26:36 +0200 Subject: [PATCH 132/265] [GR-56524] Correctly handle source array transitions in %TypedArray%.prototype.set. --- .../com.oracle.truffle.js.test/js/GR-56524.js | 37 +++++++++++++++++++ .../builtins/TypedArrayPrototypeBuiltins.java | 13 ++++--- 2 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 graal-js/src/com.oracle.truffle.js.test/js/GR-56524.js diff --git a/graal-js/src/com.oracle.truffle.js.test/js/GR-56524.js b/graal-js/src/com.oracle.truffle.js.test/js/GR-56524.js new file mode 100644 index 00000000000..8461f6327a7 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/js/GR-56524.js @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ + +/** + * Value conversion in TypedArray.prototype.set can cause source array strategy transition. + */ + +load("assert.js"); + +const sa = [30, 31, { + toString() { + sa[1073741825] = 36; // make array sparse + return "32"; + } + }, 33, 34, 35]; + +const ta = new Int16Array(9); +ta.set(sa); + +assertSameContent([30,31,32,33,34,35,0,0,0], ta); + +// Original test case +const v0 = [-267454138,886544441,-9007199254740991,-4294967297,-12,9007199254740990]; +function f1(a2) { + v0[1073741825] = v0; // make array sparse + return a2; +} +v0.toString = f1; +v0[2] = v0; +const v5 = new Int16Array(9); +v5["set"](v0); + +assertSameContent([-1722,-26567,0,-1,-12,-2,0,0,0], v5); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java index fb84941c821..23c6bba4ed2 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java @@ -43,7 +43,6 @@ import static com.oracle.truffle.js.runtime.array.TypedArray.BUFFER_TYPE_ARRAY; import static com.oracle.truffle.js.runtime.array.TypedArray.BUFFER_TYPE_DIRECT; import static com.oracle.truffle.js.runtime.array.TypedArray.BUFFER_TYPE_INTEROP; -import static com.oracle.truffle.js.runtime.builtins.JSAbstractArray.arrayGetArrayType; import static com.oracle.truffle.js.runtime.builtins.JSArrayBufferView.typedArrayGetArrayType; import java.nio.ByteBuffer; @@ -119,6 +118,7 @@ import com.oracle.truffle.js.runtime.builtins.JSArrayBufferObject; import com.oracle.truffle.js.runtime.builtins.JSArrayBufferView; import com.oracle.truffle.js.runtime.builtins.JSArrayIterator; +import com.oracle.truffle.js.runtime.builtins.JSArrayObject; import com.oracle.truffle.js.runtime.builtins.JSTypedArrayObject; import com.oracle.truffle.js.runtime.interop.JSInteropUtil; import com.oracle.truffle.js.runtime.objects.JSDynamicObject; @@ -434,7 +434,7 @@ protected Object set(JSTypedArrayObject targetObj, Object array, Object offset) if (arrayIsArrayBufferView.profile(array instanceof JSTypedArrayObject)) { setArrayBufferView(targetObj, (JSTypedArrayObject) array, targetOffset); } else if (arrayIsFastArray.profile(JSArray.isJSFastArray(array))) { - setFastArray(targetObj, (JSDynamicObject) array, targetOffset); + setFastArray(targetObj, (JSArrayObject) array, targetOffset); } else { setOther(targetObj, array, targetOffset); } @@ -447,16 +447,17 @@ protected Object set(Object thisObj, Object array, Object offset) { throw Errors.createTypeErrorIncompatibleReceiver(thisObj); } - private void setFastArray(JSTypedArrayObject thisObj, JSDynamicObject array, int offset) { + private void setFastArray(JSTypedArrayObject thisObj, JSArrayObject array, int offset) { assert JSArrayBufferView.isJSArrayBufferView(thisObj); assert JSArray.isJSFastArray(array); - ScriptArray sourceArray = sourceArrayProf.profile(arrayGetArrayType(array)); - TypedArray targetArray = targetArrayProf.profile(JSArrayBufferView.typedArrayGetArrayType(thisObj)); + ScriptArray sourceArray = sourceArrayProf.profile(array.getArrayType()); + TypedArray targetArray = targetArrayProf.profile(thisObj.getArrayType()); long sourceLen = sourceArray.length(array); rangeCheck(0, sourceLen, offset, targetArray.length(thisObj)); boolean isBigInt = JSArrayBufferView.isBigIntArrayBufferView(thisObj); for (int i = 0, j = offset; i < sourceLen; i++, j++) { + sourceArray = sourceArrayProf.profile(array.getArrayType()); Object value = sourceArray.getElement(array, i); // IntegerIndexedElementSet Object numValue = isBigInt ? toBigInt(value) : toNumber(value); @@ -470,7 +471,7 @@ private void setFastArray(JSTypedArrayObject thisObj, JSDynamicObject array, int private void setOther(JSTypedArrayObject thisObj, Object array, int offset) { assert JSArrayBufferView.isJSArrayBufferView(thisObj); assert !JSArray.isJSFastArray(array); - TypedArray targetArray = targetArrayProf.profile(JSArrayBufferView.typedArrayGetArrayType(thisObj)); + TypedArray targetArray = targetArrayProf.profile(thisObj.getArrayType()); long targetLength = targetArray.length(thisObj); Object src = toObject(array); long srcLength = objectGetLength(src); From 3d2faffc36a8ed444ca4024f4977d678cbc482b9 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 24 Jul 2024 13:07:56 +0200 Subject: [PATCH 133/265] Specialize TypedArray getters for fixed length. --- .../builtins/TypedArrayPrototypeBuiltins.java | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java index fb84941c821..4b746f7ca6e 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java @@ -54,6 +54,7 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.TruffleSafepoint; import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.profiles.BranchProfile; @@ -935,6 +936,7 @@ protected static JSObject doNotObject(Object thisObj) { } } + @ImportStatic({JSArrayBufferView.class}) public abstract static class GetTypedArrayLengthOrOffsetNode extends JSBuiltinNode { private final TypedArrayPrototype getter; @@ -944,25 +946,40 @@ protected GetTypedArrayLengthOrOffsetNode(JSContext context, JSBuiltin builtin, this.getter = getter; } - @Specialization - protected final int doTypedArray(JSTypedArrayObject typedArray, - @Cached InlinedBranchProfile outOfBoundsBranch) { - if (JSArrayBufferView.isOutOfBounds(typedArray, getContext())) { - outOfBoundsBranch.enter(this); - return 0; + @Specialization(guards = {"!isOutOfBounds(typedArray, getContext())", "!typedArray.hasAutoLength()"}) + protected final int doTypedArrayFixedLength(JSTypedArrayObject typedArray) { + switch (getter) { + case length: + return typedArray.getLengthFixed(); + case byteLength: + return typedArray.getLengthFixed() * typedArray.getArrayType().bytesPerElement(); + case byteOffset: + return typedArray.getOffset(); + default: + throw Errors.shouldNotReachHere(); } + } + + @Specialization(guards = {"!isOutOfBounds(typedArray, getContext())", "typedArray.hasAutoLength()"}) + protected final int doTypedArrayAutoLength(JSTypedArrayObject typedArray) { switch (getter) { case length: return typedArray.getLength(); case byteLength: - return JSArrayBufferView.getByteLength(typedArray, getContext()); + TypedArray type = typedArray.getArrayType(); + return type.lengthInt(typedArray) * type.bytesPerElement(); case byteOffset: - return JSArrayBufferView.getByteOffset(typedArray, getContext()); + return typedArray.getOffset(); default: throw Errors.shouldNotReachHere(); } } + @Specialization(guards = {"isOutOfBounds(typedArray, getContext())"}) + protected static int doTypedArrayOutOfBounds(@SuppressWarnings("unused") JSTypedArrayObject typedArray) { + return 0; + } + @SuppressWarnings("unused") @Specialization(guards = "!isJSArrayBufferView(thisObj)") protected int doIncompatibleReceiver(Object thisObj) { From a7839b8e9d5f22261d226c6d630b4c84e957517d Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 24 Jul 2024 13:31:31 +0200 Subject: [PATCH 134/265] Specialize ArrayLengthReadNode for fixed-length typed arrays. --- .../oracle/truffle/js/nodes/array/ArrayLengthNode.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/ArrayLengthNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/ArrayLengthNode.java index b1f2bdd5c3b..d6fb68dd37c 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/ArrayLengthNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/ArrayLengthNode.java @@ -98,8 +98,13 @@ public final double executeDouble(JSDynamicObject target) { return (double) result; } - @Specialization - protected static int doTypedArray(JSTypedArrayObject target) { + @Specialization(guards = {"!target.hasAutoLength()"}) + protected static int doTypedArrayFixedLength(JSTypedArrayObject target) { + return target.getLengthFixed(); + } + + @Specialization(guards = {"target.hasAutoLength()"}) + protected static int doTypedArrayAutoLength(JSTypedArrayObject target) { return target.getLength(); } From 34a6a63d0ed03a6d34264b7f3886a9cd266dfc34 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 24 Jul 2024 13:50:01 +0200 Subject: [PATCH 135/265] Replace division by bytesPerElement with a right shift. --- .../com/oracle/truffle/js/runtime/array/TypedArray.java | 8 +++++++- .../truffle/js/runtime/array/TypedArrayFactory.java | 7 +++++++ .../truffle/js/runtime/builtins/JSTypedArrayObject.java | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArray.java index 5145ab198ea..94ffa33cffe 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArray.java @@ -85,6 +85,7 @@ public enum ElementType { } private final int bytesPerElement; + private final byte bytesPerElementShift; private final boolean offset; private final boolean fixedLength; private final byte bufferType; @@ -98,6 +99,7 @@ public enum ElementType { protected TypedArray(TypedArrayFactory factory, boolean offset, boolean fixedLength, byte bufferType) { this.bytesPerElement = factory.getBytesPerElement(); + this.bytesPerElementShift = factory.getBytesPerElementShift(); this.offset = offset; this.fixedLength = fixedLength; this.bufferType = bufferType; @@ -124,7 +126,7 @@ public final int lengthInt(JSDynamicObject object) { case BUFFER_TYPE_SHARED -> ((JSArrayBufferObject.Shared) arrayBuffer).getByteLength(); default -> throw Errors.shouldNotReachHereUnexpectedValue(bufferType); }; - return (byteLength - getOffset(object)) / bytesPerElement; + return (byteLength - getOffset(object)) >> bytesPerElementShift; } } @@ -204,6 +206,10 @@ public final int bytesPerElement() { return bytesPerElement; } + public final byte bytesPerElementShift() { + return bytesPerElementShift; + } + public final TruffleString getName() { return name; } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArrayFactory.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArrayFactory.java index 50c1c850145..3e1af7a8c39 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArrayFactory.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArrayFactory.java @@ -237,6 +237,7 @@ TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLe }; private final int bytesPerElement; + private final byte bytesPerElementShift; private final TruffleString name; private final TypedArray arrayType; private final TypedArray arrayTypeWithOffset; @@ -257,6 +258,8 @@ TypedArray instantiateArrayType(byte bufferType, boolean offset, boolean fixedLe TypedArrayFactory(int bytesPerElement) { this.bytesPerElement = bytesPerElement; + this.bytesPerElementShift = (byte) Integer.numberOfTrailingZeros(bytesPerElement); + assert 1 << bytesPerElementShift == bytesPerElement; this.name = Strings.constant(name()); this.arrayType = instantiateArrayType(TypedArray.BUFFER_TYPE_ARRAY, false, true); this.arrayTypeWithOffset = instantiateArrayType(TypedArray.BUFFER_TYPE_ARRAY, true, true); @@ -302,6 +305,10 @@ public final int getBytesPerElement() { return bytesPerElement; } + public final byte getBytesPerElementShift() { + return bytesPerElementShift; + } + public final int getFactoryIndex() { return ordinal(); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java index 5da80411891..2dec31784c7 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java @@ -84,7 +84,7 @@ public int getLengthFixed() { } public int getLength() { - return hasAutoLength() ? (arrayBuffer.getByteLength() - offset) / arrayType.bytesPerElement() : length; + return hasAutoLength() ? (arrayBuffer.getByteLength() - offset) >> arrayType.bytesPerElementShift() : length; } public static JSTypedArrayObject create(Shape shape, JSDynamicObject proto, TypedArray arrayType, JSArrayBufferObject arrayBuffer, int length, int offset) { From fe165aa9c84e1afe07e9fa5cbf5f6da26e1fdfbd Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Tue, 30 Jul 2024 10:31:27 +0200 Subject: [PATCH 136/265] Disable Stack Trace API by default (outside V8 and Nashorn compatibility modes). --- .../src/com/oracle/truffle/js/runtime/JSContextOptions.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java index d73285c5144..62124ec01cc 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java @@ -596,7 +596,7 @@ public Map apply(String value) { public static final String STACK_TRACE_API_NAME = JS_OPTION_PREFIX + "stack-trace-api"; @Option(name = STACK_TRACE_API_NAME, category = OptionCategory.EXPERT, help = "Enable Stack Trace API (Error.captureStackTrace/prepareStackTrace/stackTraceLimit).") // - public static final OptionKey STACK_TRACE_API = new OptionKey<>(true); + public static final OptionKey STACK_TRACE_API = new OptionKey<>(false); @CompilationFinal private boolean stackTraceAPI; public enum UnhandledRejectionsTrackingMode { @@ -803,7 +803,7 @@ private void cacheOptions(SandboxPolicy sandboxPolicy) { this.allowNarrowSpacesInDateFormat = ALLOW_NARROW_SPACES_IN_DATE_FORMAT.hasBeenSet(optionValues) ? readBooleanOption(ALLOW_NARROW_SPACES_IN_DATE_FORMAT) : !isV8CompatibilityMode(); this.v8Intrinsics = readBooleanOption(V8_INTRINSICS); this.arrayElementsAmongMembers = readBooleanOption(ARRAY_ELEMENTS_AMONG_MEMBERS); - this.stackTraceAPI = readBooleanOption(STACK_TRACE_API); + this.stackTraceAPI = STACK_TRACE_API.hasBeenSet(optionValues) ? readBooleanOption(STACK_TRACE_API) : (v8CompatibilityMode || nashornCompatibilityMode); } private UnhandledRejectionsTrackingMode readUnhandledRejectionsMode() { From c38315607277fd4d910eac4a259e6750c4f557f5 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Tue, 30 Jul 2024 10:34:22 +0200 Subject: [PATCH 137/265] Updating the information about js.stack-trace-api option in change-log. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d33afc1540c..4c499011d88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ See [release calendar](https://www.graalvm.org/release-calendar/) for release da ## Version 24.2.0 * Updated Node.js to version 20.15.1. * Implemented the [`Promise.try`](https://github.com/tc39/proposal-promise-try) proposal. It is available in ECMAScript staging mode (`--js.ecmascript-version=staging`). -* Added option `js.stack-trace-api` that enables/disables `Error.captureStackTrace`, `Error.prepareStackTrace` and `Error.stackTraceLimit`. +* Added option `js.stack-trace-api` that enables/disables `Error.captureStackTrace`, `Error.prepareStackTrace` and `Error.stackTraceLimit`. These non-standard extensions are disabled by default (unless `js.v8-compat` or `js.nashorn-compat` is used). ## Version 24.1.0 * ECMAScript 2024 mode/features enabled by default. From 2cbcf5cc96a3ac309590f4f50f1c120a7b7777e3 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 30 Jul 2024 15:39:00 +0200 Subject: [PATCH 138/265] [GR-56677] Fix potential AIOOBE in RegExp flags getter. --- .../com.oracle.truffle.js.test/js/GR-56677.js | 22 +++++++++++++++++++ .../js/builtins/RegExpPrototypeBuiltins.java | 7 +++--- .../truffle/js/runtime/builtins/JSRegExp.java | 2 +- 3 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 graal-js/src/com.oracle.truffle.js.test/js/GR-56677.js diff --git a/graal-js/src/com.oracle.truffle.js.test/js/GR-56677.js b/graal-js/src/com.oracle.truffle.js.test/js/GR-56677.js new file mode 100644 index 00000000000..47804d83350 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/js/GR-56677.js @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ + +/** + * Regression test for ArrayIndexOutOfBoundsException in RegExp flags getter with 8 flags set. + */ + +load("assert.js"); + +const re = /[^123]+/digymsv; +// u and v flags are mutually exclusive, but we can fake one of the two. +Object.defineProperty(re, "unicode", { value: true, configurable: true, writable: true }); +assertSame("dgimsuvy", re.flags); + +// Original test case from fuzz testing +const v1 = /[^123]+/digymsv; +Object.defineProperty(v1, "unicode", { enumerable: true, value: "-12" }); +v1.test(v1); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/RegExpPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/RegExpPrototypeBuiltins.java index 39cb25234e3..3c207f0f1af 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/RegExpPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/RegExpPrototypeBuiltins.java @@ -1851,8 +1851,9 @@ public RegExpFlagsGetterNode(JSContext context, JSBuiltin builtin) { @Specialization(guards = "isObjectNode.executeBoolean(rx)", limit = "1") protected Object doObject(JSDynamicObject rx, @Cached @SuppressWarnings("unused") IsJSObjectNode isObjectNode, - @Cached TruffleString.FromCharArrayUTF16Node fromCharArrayNode) { - char[] flags = new char[JSRegExp.MAX_FLAGS_LENGTH]; + @Cached TruffleString.FromByteArrayNode fromByteArrayNode, + @Cached TruffleString.SwitchEncodingNode switchEncodingNode) { + byte[] flags = new byte[JSRegExp.MAX_FLAGS_LENGTH]; int len = 0; if (getHasIndices != null && getFlag(rx, getHasIndices)) { flags[len++] = 'd'; @@ -1881,7 +1882,7 @@ protected Object doObject(JSDynamicObject rx, if (len == 0) { return Strings.EMPTY_STRING; } - return Strings.fromCharArray(fromCharArrayNode, flags, 0, len); + return switchEncodingNode.execute(fromByteArrayNode.execute(flags, 0, len, TruffleString.Encoding.ISO_8859_1, true), TruffleString.Encoding.UTF_16); } @Fallback diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSRegExp.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSRegExp.java index dbc007a280f..ee17f44a5b3 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSRegExp.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSRegExp.java @@ -124,7 +124,7 @@ public final class JSRegExp extends JSNonProxy implements JSConstructorFactory.D public static final PropertyProxy LAZY_INDEX_PROXY = new LazyRegexResultIndexProxyProperty(); public static final HiddenKey GROUPS_RESULT_ID = new HiddenKey("regexResult"); - public static final int MAX_FLAGS_LENGTH = 7; // "dgimsuy" + public static final int MAX_FLAGS_LENGTH = 8; // "dgimsuvy" /** * Since we cannot use nodes here, access to this property is special-cased in From 24f8f54f438dd42c6f98b32f8110f08704d3b0ec Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 24 Jul 2024 19:24:04 +0200 Subject: [PATCH 139/265] Introduce and use TypedArrayLength, GetViewByteLength nodes. --- graal-js/mx.graal-js/suite.py | 1 + .../ArrayIteratorPrototypeBuiltins.java | 4 +- .../js/builtins/ArrayPrototypeBuiltins.java | 8 +- .../builtins/DataViewPrototypeBuiltins.java | 12 ++- .../builtins/TypedArrayPrototypeBuiltins.java | 14 +-- .../js/nodes/access/JSHasPropertyNode.java | 7 +- .../array/ArrayBufferByteLengthNode.java | 102 ++++++++++++++++++ .../ArrayBufferViewGetByteLengthNode.java | 34 +++--- .../js/nodes/array/GetViewByteLengthNode.java | 87 +++++++++++++++ .../js/nodes/array/TypedArrayLengthNode.java | 90 ++++++++++++++++ .../js/runtime/builtins/JSDataView.java | 20 ++++ .../js/runtime/builtins/JSDataViewObject.java | 5 + .../runtime/builtins/JSTypedArrayObject.java | 2 + .../buffer/NIOBufferUTF8SliceNode.java | 2 +- .../buffer/NIOBufferUTF8WriteNode.java | 2 +- .../trufflenode/node/ValueTypeNode.java | 4 +- 16 files changed, 356 insertions(+), 38 deletions(-) create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/ArrayBufferByteLengthNode.java rename graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/{access => array}/ArrayBufferViewGetByteLengthNode.java (72%) create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/GetViewByteLengthNode.java create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/TypedArrayLengthNode.java diff --git a/graal-js/mx.graal-js/suite.py b/graal-js/mx.graal-js/suite.py index 9b4941cc26c..ad023b30ca6 100644 --- a/graal-js/mx.graal-js/suite.py +++ b/graal-js/mx.graal-js/suite.py @@ -438,6 +438,7 @@ "com.oracle.truffle.js.lang to org.graalvm.nodejs", "com.oracle.truffle.js.nodes to org.graalvm.nodejs", "com.oracle.truffle.js.nodes.access to org.graalvm.nodejs", + "com.oracle.truffle.js.nodes.array to org.graalvm.nodejs", "com.oracle.truffle.js.nodes.arguments to org.graalvm.nodejs", "com.oracle.truffle.js.nodes.cast to org.graalvm.nodejs", "com.oracle.truffle.js.nodes.function to org.graalvm.nodejs", diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayIteratorPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayIteratorPrototypeBuiltins.java index 645481acc0a..f461f562244 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayIteratorPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayIteratorPrototypeBuiltins.java @@ -50,6 +50,7 @@ import com.oracle.truffle.js.nodes.access.CreateIterResultObjectNode; import com.oracle.truffle.js.nodes.access.ReadElementNode; import com.oracle.truffle.js.nodes.array.JSGetLengthNode; +import com.oracle.truffle.js.nodes.array.TypedArrayLengthNode; import com.oracle.truffle.js.nodes.cast.LongToIntOrDoubleNode; import com.oracle.truffle.js.nodes.function.JSBuiltin; import com.oracle.truffle.js.nodes.function.JSBuiltinNode; @@ -112,6 +113,7 @@ protected JSObject doArrayIterator(VirtualFrame frame, JSArrayIteratorObject ite @Cached("create(getContext())") JSGetLengthNode getLengthNode, @Cached("create(getContext())") ReadElementNode readElementNode, @Cached(inline = true) LongToIntOrDoubleNode toJSIndex, + @Cached TypedArrayLengthNode typedArrayLengthNode, @Cached InlinedBranchProfile errorBranch, @Cached InlinedBranchProfile useAfterCloseBranch, @Cached InlinedConditionProfile isTypedArrayProfile) { @@ -130,7 +132,7 @@ protected JSObject doArrayIterator(VirtualFrame frame, JSArrayIteratorObject ite errorBranch.enter(this); throw Errors.createTypeError("Cannot perform Array Iterator.prototype.next on a detached ArrayBuffer"); } - length = typedArray.getLength(); + length = typedArrayLengthNode.execute(this, typedArray, getContext()); } else { length = getLengthNode.executeLong(array); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java index 49b0e2b07fd..72615fd75d4 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java @@ -140,6 +140,7 @@ import com.oracle.truffle.js.nodes.array.JSGetLengthNode; import com.oracle.truffle.js.nodes.array.JSSetLengthNode; import com.oracle.truffle.js.nodes.array.TestArrayNode; +import com.oracle.truffle.js.nodes.array.TypedArrayLengthNode; import com.oracle.truffle.js.nodes.binary.JSIdenticalNode; import com.oracle.truffle.js.nodes.cast.JSToBigIntNode; import com.oracle.truffle.js.nodes.cast.JSToBooleanNode; @@ -370,6 +371,7 @@ public abstract static class BasicArrayOperation extends JSBuiltinNode { protected final boolean isTypedArrayImplementation; // for reusing array code on TypedArrays @Child private JSToObjectNode toObjectNode; @Child private JSGetLengthNode getLengthNode; + @Child private TypedArrayLengthNode typedArrayLengthNode; @Child private ArraySpeciesConstructorNode arraySpeciesCreateNode; @Child private IsCallableNode isCallableNode; protected final BranchProfile errorBranch = BranchProfile.create(); @@ -394,7 +396,11 @@ protected final Object toObject(Object target) { protected long getLength(Object thisObject) { if (isTypedArrayImplementation) { // %TypedArray%.prototype.* don't access the "length" property - return ((JSTypedArrayObject) thisObject).getLength(); + if (typedArrayLengthNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + typedArrayLengthNode = insert(TypedArrayLengthNode.create()); + } + return typedArrayLengthNode.execute(null, (JSTypedArrayObject) thisObject, getContext()); } else { if (getLengthNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DataViewPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DataViewPrototypeBuiltins.java index 88d7261b2d0..76946c6d2b0 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DataViewPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DataViewPrototypeBuiltins.java @@ -58,6 +58,7 @@ import com.oracle.truffle.js.builtins.DataViewPrototypeBuiltinsFactory.DataViewGetterNodeGen; import com.oracle.truffle.js.builtins.DataViewPrototypeBuiltinsFactory.DataViewSetNodeGen; import com.oracle.truffle.js.nodes.JavaScriptBaseNode; +import com.oracle.truffle.js.nodes.array.GetViewByteLengthNode; import com.oracle.truffle.js.nodes.cast.JSToBigIntNode; import com.oracle.truffle.js.nodes.cast.JSToBooleanNode; import com.oracle.truffle.js.nodes.cast.JSToDoubleNode; @@ -217,8 +218,9 @@ private static TypedArrayFactory typedArrayFactoryFromType(TruffleString type) { throw new IllegalArgumentException(Strings.toJavaString(type)); } - protected final int getBufferIndex(JSDataViewObject dataView, long getIndex, InlinedBranchProfile errorBranch) { - int viewLength = dataView.getLength(); + protected final int getBufferIndex(JSDataViewObject dataView, long getIndex, + InlinedBranchProfile errorBranch, GetViewByteLengthNode getViewByteLengthNode) { + int viewLength = getViewByteLengthNode.execute(dataView, getContext()); int elementSize = factory.getBytesPerElement(); if (getIndex + elementSize > viewLength) { errorBranch.enter(this); @@ -244,13 +246,14 @@ protected final Object doDataView(JSDataViewObject dataView, Object byteOffset, @Cached(inline = true) JSToBooleanNode toBooleanNode, @Cached InlinedBranchProfile errorBranch, @Cached InlinedExactClassProfile bufferTypeProfile, + @Cached GetViewByteLengthNode getViewByteLengthNode, @Cached GetBufferElementNode getBufferElement) { long getIndex = toIndexNode.executeLong(byteOffset); boolean isLittleEndian = factory.getBytesPerElement() == 1 || toBooleanNode.executeBoolean(this, littleEndian); JSArrayBufferObject buffer = bufferTypeProfile.profile(this, dataView.getArrayBuffer()); checkViewOutOfBounds(getContext(), dataView, errorBranch, this); - int bufferIndex = getBufferIndex(dataView, getIndex, errorBranch); + int bufferIndex = getBufferIndex(dataView, getIndex, errorBranch, getViewByteLengthNode); return getBufferElement.execute(this, buffer, bufferIndex, isLittleEndian, factory); } @@ -320,6 +323,7 @@ protected Object doDataView(JSDataViewObject dataView, Object byteOffset, Object @Cached(inline = true) JSToBooleanNode toBooleanNode, @Cached InlinedBranchProfile errorBranch, @Cached InlinedExactClassProfile bufferTypeProfile, + @Cached GetViewByteLengthNode getViewByteLengthNode, @Cached SetBufferElementNode setBufferElement) { long getIndex = toIndexNode.executeLong(byteOffset); Object numberValue = switch (factory) { @@ -331,7 +335,7 @@ protected Object doDataView(JSDataViewObject dataView, Object byteOffset, Object JSArrayBufferObject buffer = bufferTypeProfile.profile(this, dataView.getArrayBuffer()); checkViewOutOfBounds(getContext(), dataView, errorBranch, this); - int bufferIndex = getBufferIndex(dataView, getIndex, errorBranch); + int bufferIndex = getBufferIndex(dataView, getIndex, errorBranch, getViewByteLengthNode); setBufferElement.execute(this, buffer, bufferIndex, isLittleEndian, numberValue, factory); return Undefined.instance; diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java index 4b746f7ca6e..0fbb57878cb 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java @@ -97,6 +97,7 @@ import com.oracle.truffle.js.nodes.access.ForEachIndexCallNode.MaybeResultNode; import com.oracle.truffle.js.nodes.array.JSGetLengthNode; import com.oracle.truffle.js.nodes.array.JSTypedArraySortNode; +import com.oracle.truffle.js.nodes.array.TypedArrayLengthNode; import com.oracle.truffle.js.nodes.cast.JSToBigIntNode; import com.oracle.truffle.js.nodes.cast.JSToNumberNode; import com.oracle.truffle.js.nodes.cast.JSToObjectNode; @@ -882,10 +883,11 @@ protected TypedArraySortMethodNode(JSContext context, JSBuiltin builtin, boolean @Specialization protected final JSTypedArrayObject sortTypedArray(Object thisObj, Object compare, @Cached JSTypedArraySortNode typedArraySortNode, + @Cached TypedArrayLengthNode typedArrayLengthNode, @Cached InlinedConditionProfile isCompareUndefined) { checkCompareCallableOrUndefined(compare); JSTypedArrayObject thisArray = validateTypedArray(thisObj); - int len = thisArray.getLength(); + int len = typedArrayLengthNode.execute(this, thisArray, getContext()); JSTypedArrayObject resultArray; if (toSorted) { @@ -952,7 +954,7 @@ protected final int doTypedArrayFixedLength(JSTypedArrayObject typedArray) { case length: return typedArray.getLengthFixed(); case byteLength: - return typedArray.getLengthFixed() * typedArray.getArrayType().bytesPerElement(); + return typedArray.getLengthFixed() << typedArray.getArrayType().bytesPerElementShift(); case byteOffset: return typedArray.getOffset(); default: @@ -961,13 +963,13 @@ protected final int doTypedArrayFixedLength(JSTypedArrayObject typedArray) { } @Specialization(guards = {"!isOutOfBounds(typedArray, getContext())", "typedArray.hasAutoLength()"}) - protected final int doTypedArrayAutoLength(JSTypedArrayObject typedArray) { + protected final int doTypedArrayAutoLength(JSTypedArrayObject typedArray, + @Cached TypedArrayLengthNode typedArrayLengthNode) { switch (getter) { case length: - return typedArray.getLength(); + return typedArrayLengthNode.execute(this, typedArray, getContext()); case byteLength: - TypedArray type = typedArray.getArrayType(); - return type.lengthInt(typedArray) * type.bytesPerElement(); + return typedArrayLengthNode.execute(this, typedArray, getContext()) << typedArray.getArrayType().bytesPerElementShift(); case byteOffset: return typedArray.getOffset(); default: diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/JSHasPropertyNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/JSHasPropertyNode.java index 4c4b32ef30b..d67f4e55627 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/JSHasPropertyNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/JSHasPropertyNode.java @@ -56,6 +56,7 @@ import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.nodes.IntToLongTypeSystem; import com.oracle.truffle.js.nodes.JavaScriptBaseNode; +import com.oracle.truffle.js.nodes.array.TypedArrayLengthNode; import com.oracle.truffle.js.nodes.cast.JSToPropertyKeyNode; import com.oracle.truffle.js.nodes.cast.JSToStringNode; import com.oracle.truffle.js.nodes.interop.ForeignObjectPrototypeNode; @@ -132,8 +133,10 @@ private boolean checkInteger(JSDynamicObject object, long index, ScriptArray arr } @Specialization - public boolean typedArray(JSTypedArrayObject object, long index) { - return !JSArrayBufferView.isOutOfBounds(object, getLanguage().getJSContext()) && index >= 0 && index < object.getLength(); + public boolean typedArray(JSTypedArrayObject object, long index, + @Cached TypedArrayLengthNode typedArrayLengthNode) { + // If IsTypedArrayOutOfBounds(), TypedArrayLength() == 0. + return index >= 0 && index < typedArrayLengthNode.execute(this, object, getJSContext()); } @SuppressWarnings("unused") diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/ArrayBufferByteLengthNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/ArrayBufferByteLengthNode.java new file mode 100644 index 00000000000..a0e4ce6fd2d --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/ArrayBufferByteLengthNode.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.nodes.array; + +import com.oracle.truffle.api.dsl.GenerateCached; +import com.oracle.truffle.api.dsl.GenerateInline; +import com.oracle.truffle.api.dsl.ImportStatic; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.js.nodes.JavaScriptBaseNode; +import com.oracle.truffle.js.runtime.JSConfig; +import com.oracle.truffle.js.runtime.JSContext; +import com.oracle.truffle.js.runtime.JSRuntime; +import com.oracle.truffle.js.runtime.builtins.JSArray; +import com.oracle.truffle.js.runtime.builtins.JSArrayBufferObject; + +@ImportStatic({JSArray.class, JSConfig.class}) +@GenerateInline(true) +@GenerateCached(false) +public abstract class ArrayBufferByteLengthNode extends JavaScriptBaseNode { + + public abstract int execute(Node node, JSArrayBufferObject arrayBufferObj, JSContext context); + + @Specialization + protected static int heapArrayBuffer(JSArrayBufferObject.Heap thisObj, JSContext context) { + if (!context.getTypedArrayNotDetachedAssumption().isValid() && thisObj.getByteArray() == null) { + return 0; + } + return thisObj.getByteLength(); + } + + @Specialization + protected static int directArrayBuffer(JSArrayBufferObject.Direct thisObj, JSContext context) { + if (!context.getTypedArrayNotDetachedAssumption().isValid() && thisObj.getByteBuffer() == null) { + return 0; + } + return thisObj.getByteLength(); + } + + @Specialization + protected static int sharedArrayBuffer(JSArrayBufferObject.Shared thisObj, @SuppressWarnings("unused") JSContext context) { + return thisObj.getByteLength(); + } + + @Specialization + protected static int interopArrayBuffer(JSArrayBufferObject.Interop thisObj, JSContext context, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + Object buffer = thisObj.getInteropBuffer(); + if (!context.getTypedArrayNotDetachedAssumption().isValid() && buffer == null) { + return 0; + } + try { + long bufferSize = interop.getBufferSize(buffer); + // Buffer size was already checked in the ArrayBuffer constructor. + assert JSRuntime.longIsRepresentableAsInt(bufferSize) : bufferSize; + return (int) bufferSize; + } catch (UnsupportedMessageException e) { + return 0; + } + } +} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ArrayBufferViewGetByteLengthNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/ArrayBufferViewGetByteLengthNode.java similarity index 72% rename from graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ArrayBufferViewGetByteLengthNode.java rename to graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/ArrayBufferViewGetByteLengthNode.java index ebedcb51daf..df4ca171125 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ArrayBufferViewGetByteLengthNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/ArrayBufferViewGetByteLengthNode.java @@ -38,11 +38,12 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.oracle.truffle.js.nodes.access; +package com.oracle.truffle.js.nodes.array; import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.GenerateCached; import com.oracle.truffle.api.dsl.GenerateInline; +import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.nodes.Node; @@ -53,9 +54,11 @@ import com.oracle.truffle.js.runtime.builtins.JSTypedArrayObject; /** - * Optimization over JSArrayBufferView.getByteLength to have a valueProfile on the TypedArray, - * potentially avoiding a virtual call. + * Gets the byteLength of a typed array. Specializes on the type of the underlying ArrayBuffer. + * + * @see TypedArrayLengthNode */ +@ImportStatic({JSArrayBufferView.class}) @GenerateInline @GenerateCached(false) public abstract class ArrayBufferViewGetByteLengthNode extends JavaScriptBaseNode { @@ -65,21 +68,16 @@ protected ArrayBufferViewGetByteLengthNode() { public abstract int executeInt(Node node, JSTypedArrayObject obj, JSContext context); - @Specialization(guards = {"!isOutOfBounds(obj, context)", "cachedArray == getArrayType(obj)"}, limit = "1") - protected static int getByteLength(JSTypedArrayObject obj, @SuppressWarnings("unused") JSContext context, - @Cached("getArrayType(obj)") TypedArray cachedArray) { - return cachedArray.lengthInt(obj) * cachedArray.bytesPerElement(); - } - - @Specialization(guards = {"!isOutOfBounds(obj, context)"}, replaces = "getByteLength") - protected static int getByteLengthOverLimit(JSTypedArrayObject obj, @SuppressWarnings("unused") JSContext context) { - TypedArray typedArray = getArrayType(obj); - return typedArray.lengthInt(obj) * typedArray.bytesPerElement(); + @Specialization(guards = {"!isOutOfBounds(obj, context)", "cachedArray == obj.getArrayType()"}, limit = "1") + protected static int getByteLengthCached(JSTypedArrayObject obj, @SuppressWarnings("unused") JSContext context, + @Cached("obj.getArrayType()") TypedArray cachedArray) { + return cachedArray.lengthInt(obj) << cachedArray.bytesPerElementShift(); } - @Specialization(guards = {"isOutOfBounds(obj, context)"}) - protected static int getByteLengthOutOfBounds(@SuppressWarnings("unused") JSTypedArrayObject obj, @SuppressWarnings("unused") JSContext context) { - return 0; + @Specialization(replaces = "getByteLengthCached") + protected static int getByteLength(Node node, JSTypedArrayObject typedArray, JSContext context, + @Cached TypedArrayLengthNode typedArrayLengthNode) { + return typedArrayLengthNode.execute(node, typedArray, context) << typedArray.getArrayType().bytesPerElementShift(); } @NeverDefault @@ -87,8 +85,4 @@ protected static TypedArray getArrayType(JSTypedArrayObject obj) { return JSArrayBufferView.typedArrayGetArrayType(obj); } - protected boolean isOutOfBounds(JSTypedArrayObject object, JSContext context) { - return JSArrayBufferView.isOutOfBounds(object, context); - } - } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/GetViewByteLengthNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/GetViewByteLengthNode.java new file mode 100644 index 00000000000..2b66a393d7c --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/GetViewByteLengthNode.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.nodes.array; + +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.ImportStatic; +import com.oracle.truffle.api.dsl.NeverDefault; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.js.nodes.JavaScriptBaseNode; +import com.oracle.truffle.js.runtime.JSContext; +import com.oracle.truffle.js.runtime.builtins.JSArrayBufferObject; +import com.oracle.truffle.js.runtime.builtins.JSDataView; +import com.oracle.truffle.js.runtime.builtins.JSDataViewObject; + +/** + * Gets the byteLength of a DataView. Specializes on the type of the underlying ArrayBuffer. + */ +@ImportStatic({JSDataView.class}) +public abstract class GetViewByteLengthNode extends JavaScriptBaseNode { + + public abstract int execute(JSDataViewObject typedArrayObj, JSContext context); + + @Specialization(guards = {"!isOutOfBounds(dataView, context)", "!dataView.hasAutoLength()"}) + protected static int doFixedLength(JSDataViewObject dataView, JSContext context) { + assert !JSDataView.isOutOfBounds(dataView, context); + return dataView.getLengthFixed(); + } + + @Specialization(guards = {"!isOutOfBounds(dataView, context)", "dataView.hasAutoLength()"}) + protected final int doAutoLength(JSDataViewObject dataView, JSContext context, + @Cached ArrayBufferByteLengthNode getByteLengthNode) { + assert !JSDataView.isOutOfBounds(dataView, context); + JSArrayBufferObject arrayBuffer = dataView.getArrayBuffer(); + int byteLength = getByteLengthNode.execute(this, arrayBuffer, context); + int byteOffset = dataView.getOffset(); + return (byteLength - byteOffset); + } + + @SuppressWarnings("unused") + @Specialization(guards = {"isOutOfBounds(dataView, context)"}) + protected static int doOutOfBounds(JSDataViewObject dataView, JSContext context) { + return 0; + } + + @NeverDefault + public static GetViewByteLengthNode create() { + return GetViewByteLengthNodeGen.create(); + } +} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/TypedArrayLengthNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/TypedArrayLengthNode.java new file mode 100644 index 00000000000..d3c7fe6deac --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/TypedArrayLengthNode.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.nodes.array; + +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.GenerateInline; +import com.oracle.truffle.api.dsl.ImportStatic; +import com.oracle.truffle.api.dsl.NeverDefault; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.js.nodes.JavaScriptBaseNode; +import com.oracle.truffle.js.runtime.JSContext; +import com.oracle.truffle.js.runtime.builtins.JSArrayBufferObject; +import com.oracle.truffle.js.runtime.builtins.JSArrayBufferView; +import com.oracle.truffle.js.runtime.builtins.JSTypedArrayObject; + +/** + * Gets the length of a typed array. Specializes on the type of the underlying ArrayBuffer. + */ +@ImportStatic({JSArrayBufferView.class}) +@GenerateInline(inlineByDefault = true) +public abstract class TypedArrayLengthNode extends JavaScriptBaseNode { + + public abstract int execute(Node node, JSTypedArrayObject typedArrayObj, JSContext context); + + @Specialization(guards = {"!isOutOfBounds(typedArray, context)", "!typedArray.hasAutoLength()"}) + protected static int doFixedLength(JSTypedArrayObject typedArray, JSContext context) { + assert !JSArrayBufferView.isOutOfBounds(typedArray, context); + return typedArray.getLengthFixed(); + } + + @Specialization(guards = {"!isOutOfBounds(typedArray, context)", "typedArray.hasAutoLength()"}) + protected static int doAutoLength(Node node, JSTypedArrayObject typedArray, JSContext context, + @Cached ArrayBufferByteLengthNode getByteLengthNode) { + assert !JSArrayBufferView.isOutOfBounds(typedArray, context); + JSArrayBufferObject arrayBuffer = typedArray.getArrayBuffer(); + int byteLength = getByteLengthNode.execute(node, arrayBuffer, context); + int byteOffset = typedArray.getOffset(); + return (byteLength - byteOffset) >> typedArray.getArrayType().bytesPerElementShift(); + } + + @SuppressWarnings("unused") + @Specialization(guards = {"isOutOfBounds(typedArray, context)"}) + protected static int doOutOfBounds(JSTypedArrayObject typedArray, JSContext context) { + return 0; + } + + @NeverDefault + public static TypedArrayLengthNode create() { + return TypedArrayLengthNodeGen.create(); + } +} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSDataView.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSDataView.java index ea5313afde2..d71d1fea3a2 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSDataView.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSDataView.java @@ -95,6 +95,26 @@ public static int dataViewGetByteOffset(JSDataViewObject thisObj) { return thisObj.getOffset(); } + // IsViewOutOfBounds() + public static boolean isOutOfBounds(JSDataViewObject dataView, JSContext ctx) { + if (!ctx.getTypedArrayNotDetachedAssumption().isValid() && JSArrayBuffer.isDetachedBuffer(dataView.getArrayBuffer())) { + return true; + } + if (ctx.getArrayBufferNotShrunkAssumption().isValid()) { + return false; + } else { + long bufferByteLength = dataView.getArrayBuffer().getByteLength(); + int byteOffsetStart = dataView.getOffset(); + long byteOffsetEnd; + if (dataView.hasAutoLength()) { + byteOffsetEnd = bufferByteLength; + } else { + byteOffsetEnd = byteOffsetStart + dataView.getLength(); + } + return (byteOffsetStart > bufferByteLength || byteOffsetEnd > bufferByteLength); + } + } + @Override public Shape makeInitialShape(JSContext ctx, JSDynamicObject prototype) { Shape childTree = JSObjectUtil.getProtoChildShape(prototype, INSTANCE, ctx); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSDataViewObject.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSDataViewObject.java index d395f761bae..e1078f9577b 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSDataViewObject.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSDataViewObject.java @@ -56,6 +56,11 @@ public TruffleString getClassName() { return JSDataView.CLASS_NAME; } + public int getLengthFixed() { + assert !hasAutoLength(); + return length; + } + public int getLength() { return hasAutoLength() ? (arrayBuffer.getByteLength() - offset) : length; } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java index 2dec31784c7..6928ac00589 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java @@ -42,6 +42,7 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.NeverDefault; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.interop.InvalidArrayIndexException; import com.oracle.truffle.api.interop.UnsupportedMessageException; @@ -74,6 +75,7 @@ protected JSTypedArrayObject(Shape shape, JSDynamicObject proto, TypedArray arra this.arrayType = arrayType; } + @NeverDefault public TypedArray getArrayType() { return arrayType; } diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/buffer/NIOBufferUTF8SliceNode.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/buffer/NIOBufferUTF8SliceNode.java index 34c75341c46..84ed41579c4 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/buffer/NIOBufferUTF8SliceNode.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/buffer/NIOBufferUTF8SliceNode.java @@ -53,7 +53,7 @@ import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.strings.TruffleString; -import com.oracle.truffle.js.nodes.access.ArrayBufferViewGetByteLengthNode; +import com.oracle.truffle.js.nodes.array.ArrayBufferViewGetByteLengthNode; import com.oracle.truffle.js.nodes.cast.JSToIntegerAsIntNode; import com.oracle.truffle.js.nodes.function.JSBuiltin; import com.oracle.truffle.js.runtime.Boundaries; diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/buffer/NIOBufferUTF8WriteNode.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/buffer/NIOBufferUTF8WriteNode.java index 2a98bf958b4..3bddda765bd 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/buffer/NIOBufferUTF8WriteNode.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/buffer/NIOBufferUTF8WriteNode.java @@ -54,7 +54,7 @@ import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.strings.InternalByteArray; import com.oracle.truffle.api.strings.TruffleString; -import com.oracle.truffle.js.nodes.access.ArrayBufferViewGetByteLengthNode; +import com.oracle.truffle.js.nodes.array.ArrayBufferViewGetByteLengthNode; import com.oracle.truffle.js.nodes.cast.JSToIntegerAsIntNode; import com.oracle.truffle.js.nodes.function.JSBuiltin; import com.oracle.truffle.js.runtime.Boundaries; diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/node/ValueTypeNode.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/node/ValueTypeNode.java index 918bd0cb662..483e96ef2af 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/node/ValueTypeNode.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/node/ValueTypeNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -102,7 +102,7 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.nodes.JavaScriptBaseNode; -import com.oracle.truffle.js.nodes.access.ArrayBufferViewGetByteLengthNode; +import com.oracle.truffle.js.nodes.array.ArrayBufferViewGetByteLengthNode; import com.oracle.truffle.js.runtime.BigInt; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRuntime; From 995c51a35bf15781251ebaf9d469e902dc194e39 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 30 Jul 2024 02:36:33 +0200 Subject: [PATCH 140/265] Use TypedArrayLengthNode for auto-length case in ArrayLengthReadNode. --- .../com/oracle/truffle/js/nodes/array/ArrayLengthNode.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/ArrayLengthNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/ArrayLengthNode.java index d6fb68dd37c..6e328c75b95 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/ArrayLengthNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/ArrayLengthNode.java @@ -104,8 +104,9 @@ protected static int doTypedArrayFixedLength(JSTypedArrayObject target) { } @Specialization(guards = {"target.hasAutoLength()"}) - protected static int doTypedArrayAutoLength(JSTypedArrayObject target) { - return target.getLength(); + protected final int doTypedArrayAutoLength(JSTypedArrayObject target, + @Cached TypedArrayLengthNode typedArrayLengthNode) { + return typedArrayLengthNode.execute(this, target, getJSContext()); } @Specialization(guards = {"arrayType.isInstance(target.getArrayType())", "isLengthAlwaysInt(arrayType)"}, limit = "1") From ad89e790b241cfadc4f051989cb9f70ef555a306 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 30 Jul 2024 03:01:22 +0200 Subject: [PATCH 141/265] Use TypedArrayLengthNode in Atomics built-in functions, too. --- .../truffle/js/builtins/AtomicsBuiltins.java | 50 +++++++++++-------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/AtomicsBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/AtomicsBuiltins.java index 7550691cb81..6b8f389104f 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/AtomicsBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/AtomicsBuiltins.java @@ -63,6 +63,7 @@ import com.oracle.truffle.js.builtins.helper.SharedMemorySync; import com.oracle.truffle.js.nodes.access.CreateDataPropertyNode; import com.oracle.truffle.js.nodes.access.CreateObjectNode; +import com.oracle.truffle.js.nodes.array.TypedArrayLengthNode; import com.oracle.truffle.js.nodes.cast.JSToBigIntNode; import com.oracle.truffle.js.nodes.cast.JSToDoubleNode; import com.oracle.truffle.js.nodes.cast.JSToIndexNode; @@ -213,6 +214,7 @@ protected Object createNode(JSContext context, JSBuiltin builtin, boolean constr public abstract static class AtomicsOperationNode extends JSBuiltinNode { private final BranchProfile outOfBoundsBranch = BranchProfile.create(); + private final TypedArrayLengthNode typedArrayLengthNode = TypedArrayLengthNode.create(); public AtomicsOperationNode(JSContext context, JSBuiltin builtin) { super(context, builtin); @@ -258,7 +260,7 @@ public static boolean isDirectBigUint64Array(TypedArray ta) { return ta instanceof DirectBigUint64Array; } - protected void checkOutOfBounds(JSTypedArrayObject object) { + protected final void checkOutOfBounds(JSTypedArrayObject object) { if (JSArrayBufferView.isOutOfBounds(object, getContext())) { outOfBoundsBranch.enter(); throw Errors.createTypeErrorOutOfBoundsTypedArray(); @@ -274,12 +276,16 @@ protected static int validateAtomicAccess(int length, long convertedIndex) { return (int) convertedIndex; } - protected void revalidateAtomicAccess(JSTypedArrayObject target, int convertedIndex) { + protected final int typedArrayLength(JSTypedArrayObject target) { + return typedArrayLengthNode.execute(null, target, getContext()); + } + + protected final void revalidateAtomicAccess(JSTypedArrayObject target, int convertedIndex) { checkOutOfBounds(target); - validateAtomicAccess(target.getLength(), convertedIndex); + validateAtomicAccess(typedArrayLength(target), convertedIndex); } - protected JSTypedArrayObject validateTypedArray(Object object) { + protected final JSTypedArrayObject validateTypedArray(Object object) { if (!JSArrayBufferView.isJSArrayBufferView(object)) { throw createTypeErrorNotTypedArray(); } @@ -288,7 +294,7 @@ protected JSTypedArrayObject validateTypedArray(Object object) { return typedArrayObject; } - protected TypedArray validateIntegerTypedArray(JSTypedArrayObject typedArrayObject, boolean waitable) { + protected final TypedArray validateIntegerTypedArray(JSTypedArrayObject typedArrayObject, boolean waitable) { TypedArray ta = JSArrayBufferView.typedArrayGetArrayType(typedArrayObject); if (waitable) { if (!(ta instanceof DirectInt32Array || ta instanceof DirectBigInt64Array || ta instanceof Int32Array || ta instanceof BigInt64Array || ta instanceof InteropInt32Array || @@ -456,7 +462,7 @@ protected int doInt32ArrayObj(JSTypedArrayObject target, int index, Object expec protected int doInt32ArrayIntObjIdx(JSTypedArrayObject target, Object index, int expected, int replacement, @Bind("typedArrayGetArrayType(target)") TypedArray ta, @Cached @Shared JSToIndexNode toIndexNode) { - int intIndex = validateAtomicAccess(target.getLength(), toIndexNode.executeLong(index)); + int intIndex = validateAtomicAccess(typedArrayLength(target), toIndexNode.executeLong(index)); return doCASInt(target, intIndex, expected, replacement, (TypedArray.DirectInt32Array) ta); } @@ -464,7 +470,7 @@ protected int doInt32ArrayIntObjIdx(JSTypedArrayObject target, Object index, int protected int doInt32ArrayObjObjIdx(JSTypedArrayObject target, Object index, Object expected, Object replacement, @Bind("typedArrayGetArrayType(target)") TypedArray ta, @Cached @Shared JSToIndexNode toIndexNode) { - int intIndex = validateAtomicAccess(target.getLength(), toIndexNode.executeLong(index)); + int intIndex = validateAtomicAccess(typedArrayLength(target), toIndexNode.executeLong(index)); return doCASInt(target, intIndex, toInt(expected), toInt(replacement), (TypedArray.DirectInt32Array) ta); } @@ -472,7 +478,7 @@ protected int doInt32ArrayObjObjIdx(JSTypedArrayObject target, Object index, Obj protected BigInt doBigInt64ArrayObjObjIdx(JSTypedArrayObject target, Object index, Object expected, Object replacement, @Bind("typedArrayGetArrayType(target)") TypedArray ta, @Cached @Shared JSToIndexNode toIndexNode) { - int intIndex = validateAtomicAccess(target.getLength(), toIndexNode.executeLong(index)); + int intIndex = validateAtomicAccess(typedArrayLength(target), toIndexNode.executeLong(index)); return doCASBigInt(target, intIndex, toBigInt(expected).toBigInt64(), toBigInt(replacement), (TypedArray.DirectBigInt64Array) ta); } @@ -480,7 +486,7 @@ protected BigInt doBigInt64ArrayObjObjIdx(JSTypedArrayObject target, Object inde protected BigInt doBigUint64ArrayObjObjIdx(JSTypedArrayObject target, Object index, Object expected, Object replacement, @Bind("typedArrayGetArrayType(target)") TypedArray ta, @Cached @Shared JSToIndexNode toIndexNode) { - int intIndex = validateAtomicAccess(target.getLength(), toIndexNode.executeLong(index)); + int intIndex = validateAtomicAccess(typedArrayLength(target), toIndexNode.executeLong(index)); return doCASBigInt(target, intIndex, toBigInt(expected).toBigUint64(), toBigInt(replacement), (TypedArray.DirectBigUint64Array) ta); } @@ -492,7 +498,7 @@ protected Object doGeneric(Object maybeTarget, Object index, Object expected, Ob JSTypedArrayObject target = validateTypedArray(maybeTarget); boolean sharedArrayBuffer = isSharedBufferView(target); TypedArray ta = validateIntegerTypedArray(target, false); - int intIndex = validateAtomicAccess(target.getLength(), toIndexNode.executeLong(index)); + int intIndex = validateAtomicAccess(typedArrayLength(target), toIndexNode.executeLong(index)); BigInt expectedBigInt = null; BigInt replacementBigInt = null; @@ -631,7 +637,7 @@ protected BigInt doBigUint64ArrayObj(JSTypedArrayObject target, int index, protected int doInt32ArrayObjObjIdx(JSTypedArrayObject target, Object index, @Bind("typedArrayGetArrayType(target)") TypedArray ta, @Cached @Shared JSToIndexNode toIndexNode) { - int intIndex = validateAtomicAccess(target.getLength(), toIndexNode.executeLong(index)); + int intIndex = validateAtomicAccess(typedArrayLength(target), toIndexNode.executeLong(index)); return SharedMemorySync.doVolatileGet(target, intIndex, (DirectInt32Array) ta); } @@ -641,7 +647,7 @@ protected Object doGeneric(Object maybeTarget, Object index, JSTypedArrayObject target = validateTypedArray(maybeTarget); TypedArray ta = validateIntegerTypedArray(target, false); - int intIndex = validateAtomicAccess(target.getLength(), toIndexNode.executeLong(index)); + int intIndex = validateAtomicAccess(typedArrayLength(target), toIndexNode.executeLong(index)); revalidateAtomicAccess(target, intIndex); if (ta instanceof DirectInt8Array || ta instanceof Int8Array || ta instanceof InteropInt8Array) { @@ -773,7 +779,7 @@ protected Object doSharedUint32Array(JSTypedArrayObject target, int index, Objec protected Object doSharedInt32ArrayObjIdx(JSTypedArrayObject target, Object index, int value, @Bind("typedArrayGetArrayType(target)") TypedArray ta, @Cached @Shared JSToIndexNode toIndexNode) { - int intIndex = validateAtomicAccess(target.getLength(), toIndexNode.executeLong(index)); + int intIndex = validateAtomicAccess(typedArrayLength(target), toIndexNode.executeLong(index)); SharedMemorySync.doVolatilePut(target, intIndex, value, (DirectInt32Array) ta); return value; } @@ -782,7 +788,7 @@ protected Object doSharedInt32ArrayObjIdx(JSTypedArrayObject target, Object inde protected Object doSharedBigInt64Array(JSTypedArrayObject target, Object index, Object value, @Bind("typedArrayGetArrayType(target)") TypedArray ta, @Cached @Shared JSToIndexNode toIndexNode) { - int intIndex = validateAtomicAccess(target.getLength(), toIndexNode.executeLong(index)); + int intIndex = validateAtomicAccess(typedArrayLength(target), toIndexNode.executeLong(index)); BigInt biValue = toBigIntChecked(value, target, intIndex); SharedMemorySync.doVolatilePutBigInt(target, intIndex, biValue, (DirectBigInt64Array) ta); return biValue; @@ -792,7 +798,7 @@ protected Object doSharedBigInt64Array(JSTypedArrayObject target, Object index, protected Object doSharedBigUint64Array(JSTypedArrayObject target, Object index, Object value, @Bind("typedArrayGetArrayType(target)") TypedArray ta, @Cached @Shared JSToIndexNode toIndexNode) { - int intIndex = validateAtomicAccess(target.getLength(), toIndexNode.executeLong(index)); + int intIndex = validateAtomicAccess(typedArrayLength(target), toIndexNode.executeLong(index)); BigInt biValue = toBigIntChecked(value, target, intIndex); SharedMemorySync.doVolatilePutBigInt(target, intIndex, biValue, (DirectBigUint64Array) ta); return biValue; @@ -804,7 +810,7 @@ protected Object doGeneric(Object maybeTarget, Object index, Object value, JSTypedArrayObject target = validateTypedArray(maybeTarget); TypedArray ta = validateIntegerTypedArray(target, false); - int intIndex = validateAtomicAccess(target.getLength(), toIndexNode.executeLong(index)); + int intIndex = validateAtomicAccess(typedArrayLength(target), toIndexNode.executeLong(index)); if (ta instanceof DirectInt8Array || ta instanceof DirectUint8Array || ta instanceof Int8Array || ta instanceof Uint8Array || @@ -961,7 +967,7 @@ protected SafeInteger doSharedUint32Array(JSTypedArrayObject target, int index, protected int doSharedInt32ArrayObjIdx(JSTypedArrayObject target, Object index, int value, @Bind("typedArrayGetArrayType(target)") TypedArray ta, @Cached @Shared JSToIndexNode toIndexNode) { - int intIndex = validateAtomicAccess(target.getLength(), toIndexNode.executeLong(index)); + int intIndex = validateAtomicAccess(typedArrayLength(target), toIndexNode.executeLong(index)); return atomicDoInt(target, intIndex, value, (DirectInt32Array) ta); } @@ -969,7 +975,7 @@ protected int doSharedInt32ArrayObjIdx(JSTypedArrayObject target, Object index, protected BigInt doSharedBigInt64Array(JSTypedArrayObject target, Object index, Object value, @Bind("typedArrayGetArrayType(target)") TypedArray ta, @Cached @Shared JSToIndexNode toIndexNode) { - int intIndex = validateAtomicAccess(target.getLength(), toIndexNode.executeLong(index)); + int intIndex = validateAtomicAccess(typedArrayLength(target), toIndexNode.executeLong(index)); return atomicDoBigInt(target, intIndex, toBigInt(value), (DirectBigInt64Array) ta); } @@ -977,7 +983,7 @@ protected BigInt doSharedBigInt64Array(JSTypedArrayObject target, Object index, protected BigInt doSharedBigUint64Array(JSTypedArrayObject target, Object index, Object value, @Bind("typedArrayGetArrayType(target)") TypedArray ta, @Cached @Shared JSToIndexNode toIndexNode) { - int intIndex = validateAtomicAccess(target.getLength(), toIndexNode.executeLong(index)); + int intIndex = validateAtomicAccess(typedArrayLength(target), toIndexNode.executeLong(index)); return atomicDoBigInt(target, intIndex, toBigInt(value), (DirectBigUint64Array) ta); } @@ -988,7 +994,7 @@ protected Object doGeneric(Object maybeTarget, Object index, Object value, JSTypedArrayObject target = validateTypedArray(maybeTarget); TypedArray ta = validateIntegerTypedArray(target, false); - int intIndex = validateAtomicAccess(target.getLength(), toIndexNode.executeLong(index)); + int intIndex = validateAtomicAccess(typedArrayLength(target), toIndexNode.executeLong(index)); if (!isSharedBufferView(target)) { notSharedArrayBuffer.enter(this); @@ -1076,7 +1082,7 @@ protected Object doNotify(Object maybeTarget, Object index, Object count, JSTypedArrayObject target = validateTypedArray(maybeTarget); validateIntegerTypedArray(target, true); - int i = validateAtomicAccess(target.getLength(), toIndexNode.executeLong(index)); + int i = validateAtomicAccess(typedArrayLength(target), toIndexNode.executeLong(index)); int c = Integer.MAX_VALUE; if (count != Undefined.instance) { @@ -1130,7 +1136,7 @@ protected Object doWait(VirtualFrame frame, Object maybeTarget, Object index, Ob notSharedArrayBuffer.enter(); throw createTypeErrorNotSharedArray(); } - int i = validateAtomicAccess(target.getLength(), toIndexNode.executeLong(index)); + int i = validateAtomicAccess(typedArrayLength(target), toIndexNode.executeLong(index)); boolean isInt32 = isInt32SharedBufferView(target); long v = isInt32 ? toInt32(value) : toBigInt(value).longValue(); From 4bd55d29abe23cb148c64d1554b9570ae599103d Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 30 Jul 2024 03:17:43 +0200 Subject: [PATCH 142/265] Consolidate TestV8AtomicsNum*Node. --- .../js/builtins/testing/TestV8Builtins.java | 73 ++++++------------- 1 file changed, 23 insertions(+), 50 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/testing/TestV8Builtins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/testing/TestV8Builtins.java index a3779bf3b6a..b7050bd158a 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/testing/TestV8Builtins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/testing/TestV8Builtins.java @@ -47,6 +47,7 @@ import com.oracle.truffle.api.dsl.Cached; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.strings.TruffleString; +import com.oracle.truffle.js.builtins.AtomicsBuiltins; import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugClassNameNodeGen; import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugClassNodeGen; import com.oracle.truffle.js.builtins.DebugBuiltinsFactory.DebugContinueInInterpreterNodeGen; @@ -55,8 +56,7 @@ import com.oracle.truffle.js.builtins.JSBuiltinsContainer; import com.oracle.truffle.js.builtins.helper.GCNodeGen; import com.oracle.truffle.js.builtins.helper.SharedMemorySync; -import com.oracle.truffle.js.builtins.testing.TestV8BuiltinsFactory.TestV8AtomicsNumUnresolvedAsyncPromisesForTestingNodeGen; -import com.oracle.truffle.js.builtins.testing.TestV8BuiltinsFactory.TestV8AtomicsNumWaitersForTestingNodeGen; +import com.oracle.truffle.js.builtins.testing.TestV8BuiltinsFactory.TestV8AtomicsNumNodeGen; import com.oracle.truffle.js.builtins.testing.TestV8BuiltinsFactory.TestV8ConstructDoubleNodeGen; import com.oracle.truffle.js.builtins.testing.TestV8BuiltinsFactory.TestV8CreateAsyncFromSyncIteratorNodeGen; import com.oracle.truffle.js.builtins.testing.TestV8BuiltinsFactory.TestV8CreatePrivateSymbolNodeGen; @@ -85,7 +85,6 @@ import com.oracle.truffle.js.runtime.JSAgent; import com.oracle.truffle.js.runtime.JSAgentWaiterList.JSAgentWaiterListEntry; import com.oracle.truffle.js.runtime.JSContext; -import com.oracle.truffle.js.runtime.JSException; import com.oracle.truffle.js.runtime.JSRealm; import com.oracle.truffle.js.runtime.JSRuntime; import com.oracle.truffle.js.runtime.JobCallback; @@ -205,9 +204,8 @@ protected Object createNode(JSContext context, JSBuiltin builtin, boolean constr case toLength: return TestV8ToLengthNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context)); case atomicsNumWaitersForTesting: - return TestV8AtomicsNumWaitersForTestingNodeGen.create(context, builtin, args().fixedArgs(2).createArgumentNodes(context)); case atomicsNumUnresolvedAsyncPromisesForTesting: - return TestV8AtomicsNumUnresolvedAsyncPromisesForTestingNodeGen.create(context, builtin, args().fixedArgs(2).createArgumentNodes(context)); + return TestV8AtomicsNumNodeGen.create(context, builtin, builtinEnum, args().fixedArgs(2).createArgumentNodes(context)); case setAllowAtomicsWait: return TestV8SetAllowAtomicsWaitNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context)); case createPrivateSymbol: @@ -439,12 +437,16 @@ protected Object setTimeout(Object callback) { } } - public abstract static class TestV8AtomicsBaseNode extends JSBuiltinNode { - public TestV8AtomicsBaseNode(JSContext context, JSBuiltin builtin) { + public abstract static class TestV8AtomicsNumNode extends AtomicsBuiltins.AtomicsOperationNode { + + private final TestV8 getter; + + public TestV8AtomicsNumNode(JSContext context, JSBuiltin builtin, TestV8 getter) { super(context, builtin); + this.getter = getter; } - protected JSTypedArrayObject ensureSharedArray(Object maybeTarget) { + private JSTypedArrayObject ensureSharedArray(Object maybeTarget) { if (maybeTarget instanceof JSTypedArrayObject typedArrayObj) { JSDynamicObject buffer = JSArrayBufferView.getArrayBuffer(typedArrayObj); if (JSSharedArrayBuffer.isJSSharedArrayBuffer(buffer)) { @@ -454,55 +456,26 @@ protected JSTypedArrayObject ensureSharedArray(Object maybeTarget) { throw createTypeErrorNotSharedArray(); } - @TruffleBoundary - protected final JSException createTypeErrorNotSharedArray() { - return Errors.createTypeError("Cannot execute on non-shared array.", this); - } - - @TruffleBoundary - protected static final JSException createRangeErrorSharedArray(Object idx) { - return Errors.createRangeError("Range error with index : " + idx); - } - - protected static int validateAtomicAccess(JSTypedArrayObject target, long convertedIndex, Object originalIndex) { - int length = target.getLength(); - assert convertedIndex >= 0; - if (convertedIndex >= length) { - throw createRangeErrorSharedArray(originalIndex); - } - return (int) convertedIndex; - } - - } - - public abstract static class TestV8AtomicsNumWaitersForTestingNode extends TestV8AtomicsBaseNode { - - public TestV8AtomicsNumWaitersForTestingNode(JSContext context, JSBuiltin builtin) { - super(context, builtin); - } - @Specialization - protected Object numWaiters(Object maybeTarget, Object index, + protected int num(Object maybeTarget, Object index, @Cached JSToIndexNode toIndexNode) { JSTypedArrayObject target = ensureSharedArray(maybeTarget); - int i = validateAtomicAccess(target, toIndexNode.executeLong(index), index); - JSAgentWaiterListEntry wl = SharedMemorySync.getWaiterList(getContext(), target, i); - return wl.size(); + int i = validateAtomicAccess(typedArrayLength(target), toIndexNode.executeLong(index)); + return switch (getter) { + case atomicsNumWaitersForTesting -> numWaiters(target, i); + case atomicsNumUnresolvedAsyncPromisesForTesting -> numUnresolvedAsyncPromises(target, i); + default -> throw Errors.shouldNotReachHereUnexpectedValue(getter); + }; } - } - - public abstract static class TestV8AtomicsNumUnresolvedAsyncPromisesForTestingNode extends TestV8AtomicsBaseNode { - - public TestV8AtomicsNumUnresolvedAsyncPromisesForTestingNode(JSContext context, JSBuiltin builtin) { - super(context, builtin); + @TruffleBoundary + private int numWaiters(JSTypedArrayObject target, int i) { + JSAgentWaiterListEntry wl = SharedMemorySync.getWaiterList(getContext(), target, i); + return wl.size(); } - @Specialization - protected Object numUnresolvedAsyncPromises(Object maybeTarget, Object index, - @Cached JSToIndexNode toIndexNode) { - JSTypedArrayObject target = ensureSharedArray(maybeTarget); - int i = validateAtomicAccess(target, toIndexNode.executeLong(index), index); + @TruffleBoundary + private int numUnresolvedAsyncPromises(JSTypedArrayObject target, int i) { JSAgent agent = getRealm().getAgent(); JSAgentWaiterListEntry wl = SharedMemorySync.getWaiterList(getContext(), target, i); return agent.getAsyncWaitersToBeResolved(wl); From bc0b955f0034be3775ed299e270ebed3ce3658a8 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 30 Jul 2024 12:43:25 +0200 Subject: [PATCH 143/265] Simplify TypedArray getter specializations. --- .../builtins/TypedArrayPrototypeBuiltins.java | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java index 0fbb57878cb..ce9f69b6646 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java @@ -948,22 +948,8 @@ protected GetTypedArrayLengthOrOffsetNode(JSContext context, JSBuiltin builtin, this.getter = getter; } - @Specialization(guards = {"!isOutOfBounds(typedArray, getContext())", "!typedArray.hasAutoLength()"}) - protected final int doTypedArrayFixedLength(JSTypedArrayObject typedArray) { - switch (getter) { - case length: - return typedArray.getLengthFixed(); - case byteLength: - return typedArray.getLengthFixed() << typedArray.getArrayType().bytesPerElementShift(); - case byteOffset: - return typedArray.getOffset(); - default: - throw Errors.shouldNotReachHere(); - } - } - - @Specialization(guards = {"!isOutOfBounds(typedArray, getContext())", "typedArray.hasAutoLength()"}) - protected final int doTypedArrayAutoLength(JSTypedArrayObject typedArray, + @Specialization(guards = {"!isOutOfBounds(typedArray, getContext())"}) + protected final int doTypedArray(JSTypedArrayObject typedArray, @Cached TypedArrayLengthNode typedArrayLengthNode) { switch (getter) { case length: From 8a9ae883ac4bb3963ef32c874ed9fd84978ae30b Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 31 Jul 2024 15:52:50 +0200 Subject: [PATCH 144/265] Include wasm in js standalone if dynamically imported. --- graal-js/mx.graal-js/mx_graal_js.py | 11 +++++++++-- graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py | 11 ++++------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/graal-js/mx.graal-js/mx_graal_js.py b/graal-js/mx.graal-js/mx_graal_js.py index 3de3056678c..ac2964d7c21 100644 --- a/graal-js/mx.graal-js/mx_graal_js.py +++ b/graal-js/mx.graal-js/mx_graal_js.py @@ -525,6 +525,9 @@ def mx_register_dynamic_suite_constituents(register_project, register_distributi 'src', meta_pom.name, meta_pom.maven_group_id(), meta_pom.theLicense, isolate_build_options=isolate_build_options) +def is_wasm_available(): + return any(wasm_suite in mx.get_dynamic_imports() for wasm_suite in [('wasm', True), ('wasm-enterprise', True)]) + mx_sdk.register_graalvm_component(mx_sdk.GraalVmLanguage( suite=_suite, @@ -551,6 +554,7 @@ def mx_register_dynamic_suite_constituents(register_project, register_distributi truffle_jars=[ 'graal-js:GRAALJS', 'sdk:MAVEN_DOWNLOADER', + *(['wasm:WASM'] if is_wasm_available() else []), ], support_distributions=[ 'graal-js:GRAALJS_GRAALVM_SUPPORT', @@ -558,14 +562,17 @@ def mx_register_dynamic_suite_constituents(register_project, register_distributi library_configs=[ mx_sdk.LanguageLibraryConfig( launchers=['bin/'], - jar_distributions=['graal-js:GRAALJS_LAUNCHER'], + jar_distributions=[ + 'graal-js:GRAALJS_LAUNCHER', + *(['wasm:WASM'] if is_wasm_available() else []) + ], main_class='com.oracle.truffle.js.shell.JSLauncher', build_args=[], build_args_enterprise=[ '-H:+AuxiliaryEngineCache', '-H:ReservedAuxiliaryImageBytes=2145482548', ] if not mx.is_windows() else [], - language='js' + language='js', ) ], boot_jars=[], diff --git a/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py b/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py index ac90650126a..ccd97b2d790 100644 --- a/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py +++ b/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py @@ -36,7 +36,7 @@ from mx_gate import Task from argparse import ArgumentParser from os.path import exists, join, isdir, pathsep, sep -from mx_graal_js import get_jdk +from mx_graal_js import get_jdk, is_wasm_available _suite = mx.suite('graal-nodejs') _current_os = mx.get_os() @@ -616,9 +616,6 @@ def _prepare_svm_env(): def mx_post_parse_cmd_line(args): mx_graal_nodejs_benchmark.register_nodejs_vms() -def _is_wasm_available(): - return any(wasm_suite in mx.get_dynamic_imports() for wasm_suite in [('wasm', True), ('wasm-enterprise', True)]) - mx_sdk.register_graalvm_component(mx_sdk.GraalVmLanguage( suite=_suite, name='Graal.nodejs', @@ -633,7 +630,7 @@ def _is_wasm_available(): truffle_jars=[ 'graal-nodejs:TRUFFLENODE', 'sdk:MAVEN_DOWNLOADER', - *(['wasm:WASM'] if _is_wasm_available() else []), + *(['wasm:WASM'] if is_wasm_available() else []), ], support_distributions=[ 'graal-nodejs:TRUFFLENODE_GRAALVM_SUPPORT', @@ -651,13 +648,13 @@ def _is_wasm_available(): destination='lib/', jar_distributions=[ 'graal-nodejs:TRUFFLENODE', - *(['wasm:WASM'] if _is_wasm_available() else []), + *(['wasm:WASM'] if is_wasm_available() else []), ], build_args=[ '--tool:all', '--language:nodejs', '-Dgraalvm.libpolyglot=true', # `lib:graal-nodejs` should be initialized like `lib:polyglot` (GR-10038) - *(['--language:wasm'] if _is_wasm_available() else []), + *(['--language:wasm'] if is_wasm_available() else []), ], build_args_enterprise=[ '-H:+AuxiliaryEngineCache', From d4c50d32ff13f49682920adcca21b42a4adad8dc Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 1 Aug 2024 14:08:10 +0200 Subject: [PATCH 145/265] Avoid type dispatch for uncached JSTypedArrayObject.{read,write}ArrayElement. --- .../truffle/js/runtime/builtins/JSTypedArrayObject.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java index 6928ac00589..56bf42445dc 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java @@ -132,7 +132,7 @@ public Object readArrayElement(long index, } Object result; if (readNode == null) { - result = JSObject.getOrDefault(target, index, target, Undefined.instance); + result = JSArrayBufferView.INSTANCE.getOwnHelper(target, target, index, self); } else { result = readNode.executeWithTargetAndIndexOrDefault(target, index, Undefined.instance); } @@ -154,14 +154,14 @@ public boolean isArrayElementReadable(long index, public void writeArrayElement(long index, Object value, @Cached ImportValueNode castValueNode, @Cached(value = "createCachedInterop()", uncached = "getUncachedWrite()") WriteElementNode writeNode, - @CachedLibrary("this") InteropLibrary thisLibrary) throws InvalidArrayIndexException, UnsupportedMessageException { + @CachedLibrary("this") InteropLibrary self) throws InvalidArrayIndexException, UnsupportedMessageException { var target = this; - if (index < 0 || index >= thisLibrary.getArraySize(this)) { + if (index < 0 || index >= self.getArraySize(this)) { throw InvalidArrayIndexException.create(index); } Object importedValue = castValueNode.executeWithTarget(value); if (writeNode == null) { - JSObject.set(target, index, importedValue, true, null); + JSArrayBufferView.INSTANCE.set(target, index, importedValue, target, true, self); } else { writeNode.executeWithTargetAndIndexAndValue(target, index, importedValue); } From a1d3470c730cce9120ab80a893196f1a644399f6 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 1 Aug 2024 21:42:34 +0200 Subject: [PATCH 146/265] Use GetViewByteLengthNode for DataView byteLength getter. --- .../oracle/truffle/js/builtins/DataViewPrototypeBuiltins.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DataViewPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DataViewPrototypeBuiltins.java index 76946c6d2b0..f676fb3eefc 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DataViewPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DataViewPrototypeBuiltins.java @@ -396,13 +396,14 @@ public DataViewGetterNode(JSContext context, JSBuiltin builtin, DataViewPrototyp @Specialization protected final Object doDataView(JSDataViewObject dataView, + @Cached GetViewByteLengthNode getViewByteLengthNode, @Cached InlinedBranchProfile errorBranch) { switch (getter) { case buffer: return dataView.getArrayBuffer(); case byteLength: checkViewOutOfBounds(getContext(), dataView, errorBranch, this); - return dataView.getLength(); + return getViewByteLengthNode.execute(dataView, getContext()); case byteOffset: checkViewOutOfBounds(getContext(), dataView, errorBranch, this); return dataView.getOffset(); From 977abcf9f7a8e6153d1db0b8e9543ada91ec7ed7 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 1 Aug 2024 21:36:03 +0200 Subject: [PATCH 147/265] Export byte source as a (read-only) Interop buffer view. --- .../js/nodes/wasm/ExportByteSourceNode.java | 4 +- .../js/runtime/interop/InteropBufferView.java | 173 ++++++++++++++++++ 2 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/interop/InteropBufferView.java diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/wasm/ExportByteSourceNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/wasm/ExportByteSourceNode.java index 94d8fbaa82e..4f4b839adcc 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/wasm/ExportByteSourceNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/wasm/ExportByteSourceNode.java @@ -54,6 +54,7 @@ import com.oracle.truffle.js.runtime.builtins.JSDataView; import com.oracle.truffle.js.runtime.builtins.JSDataViewObject; import com.oracle.truffle.js.runtime.builtins.JSTypedArrayObject; +import com.oracle.truffle.js.runtime.interop.InteropBufferView; /** * Exports byte source such that it can be read by WASM. @@ -126,7 +127,8 @@ private Object exportBuffer(JSArrayBufferObject arrayBuffer, int offset, int len bufferType = TypedArray.BUFFER_TYPE_SHARED; } TypedArray arrayType = TypedArrayFactory.Uint8Array.createArrayType(bufferType, (offset != 0), true); - return JSArrayBufferView.createArrayBufferView(context, realm, buffer, arrayType, offset, length); + JSTypedArrayObject array = JSArrayBufferView.createArrayBufferView(context, realm, buffer, arrayType, offset, length); + return new InteropBufferView(buffer, offset, length, array); } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/interop/InteropBufferView.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/interop/InteropBufferView.java new file mode 100644 index 00000000000..16f58608667 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/interop/InteropBufferView.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.runtime.interop; + +import java.nio.ByteOrder; + +import com.oracle.truffle.api.interop.InteropLibrary; +import com.oracle.truffle.api.interop.InvalidBufferOffsetException; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.library.ExportLibrary; +import com.oracle.truffle.api.library.ExportMessage; +import com.oracle.truffle.js.runtime.builtins.JSArrayBufferObject; +import com.oracle.truffle.js.runtime.builtins.JSTypedArrayObject; + +/** + * A read-only view on an ArrayBuffer with a fixed offset and length. Delegates other Interop + * messages to the provided source array. + * + * Used to transfer module byte sources from JS to WebAssembly. + */ +@SuppressWarnings({"static-method", "unused"}) +@ExportLibrary(value = InteropLibrary.class, delegateTo = "arrayView") +public final class InteropBufferView implements TruffleObject { + + private final int viewByteOffset; + private final int viewByteLength; + final JSArrayBufferObject arrayBuffer; + final JSTypedArrayObject arrayView; + + public InteropBufferView(JSArrayBufferObject arrayBuffer, int byteOffset, int byteLength, JSTypedArrayObject arrayView) { + this.viewByteOffset = byteOffset; + this.viewByteLength = byteLength; + this.arrayBuffer = arrayBuffer; + this.arrayView = arrayView; + } + + @SuppressWarnings("static-method") + @ExportMessage + public boolean hasBufferElements() { + return true; + } + + @ExportMessage + public long getBufferSize() { + return viewByteLength; + } + + private long checkFromIndexSize(long fromIndex, int size) throws InvalidBufferOffsetException { + long bufferByteOffset = viewByteOffset + fromIndex; + long bufferByteLength = viewByteLength; + if ((bufferByteLength | bufferByteOffset | size) < 0 || size > bufferByteLength - bufferByteOffset) { + throw InvalidBufferOffsetException.create(fromIndex, size); + } + return bufferByteOffset; + } + + @ExportMessage + void readBuffer(long byteOffset, byte[] destination, int destinationOffset, int readLength, + @CachedLibrary("this.arrayBuffer") InteropLibrary bufferInterop) throws UnsupportedMessageException, InvalidBufferOffsetException { + bufferInterop.readBuffer(arrayBuffer, checkFromIndexSize(byteOffset, readLength), destination, destinationOffset, readLength); + } + + @ExportMessage + byte readBufferByte(long byteOffset, + @CachedLibrary("this.arrayBuffer") InteropLibrary bufferInterop) throws UnsupportedMessageException, InvalidBufferOffsetException { + return bufferInterop.readBufferByte(arrayBuffer, checkFromIndexSize(byteOffset, Byte.BYTES)); + } + + @ExportMessage + short readBufferShort(ByteOrder order, long byteOffset, + @CachedLibrary("this.arrayBuffer") InteropLibrary bufferInterop) throws UnsupportedMessageException, InvalidBufferOffsetException { + return bufferInterop.readBufferShort(arrayBuffer, order, checkFromIndexSize(byteOffset, Short.BYTES)); + } + + @ExportMessage + int readBufferInt(ByteOrder order, long byteOffset, + @CachedLibrary("this.arrayBuffer") InteropLibrary bufferInterop) throws UnsupportedMessageException, InvalidBufferOffsetException { + return bufferInterop.readBufferInt(arrayBuffer, order, checkFromIndexSize(byteOffset, Integer.BYTES)); + } + + @ExportMessage + long readBufferLong(ByteOrder order, long byteOffset, + @CachedLibrary("this.arrayBuffer") InteropLibrary bufferInterop) throws UnsupportedMessageException, InvalidBufferOffsetException { + return bufferInterop.readBufferLong(arrayBuffer, order, checkFromIndexSize(byteOffset, Long.BYTES)); + } + + @ExportMessage + float readBufferFloat(ByteOrder order, long byteOffset, + @CachedLibrary("this.arrayBuffer") InteropLibrary bufferInterop) throws UnsupportedMessageException, InvalidBufferOffsetException { + return bufferInterop.readBufferFloat(arrayBuffer, order, checkFromIndexSize(byteOffset, Float.BYTES)); + } + + @ExportMessage + double readBufferDouble(ByteOrder order, long byteOffset, + @CachedLibrary("this.arrayBuffer") InteropLibrary bufferInterop) throws UnsupportedMessageException, InvalidBufferOffsetException { + return bufferInterop.readBufferDouble(arrayBuffer, order, checkFromIndexSize(byteOffset, Double.BYTES)); + } + + @ExportMessage + boolean isBufferWritable() { + return false; + } + + @ExportMessage + void writeBufferByte(long byteOffset, byte value) throws UnsupportedMessageException { + throw UnsupportedMessageException.create(); + } + + @ExportMessage + void writeBufferShort(ByteOrder order, long byteOffset, short value) throws UnsupportedMessageException { + throw UnsupportedMessageException.create(); + } + + @ExportMessage + void writeBufferInt(ByteOrder order, long byteOffset, int value) throws UnsupportedMessageException { + throw UnsupportedMessageException.create(); + } + + @ExportMessage + void writeBufferLong(ByteOrder order, long byteOffset, long value) throws UnsupportedMessageException { + throw UnsupportedMessageException.create(); + } + + @ExportMessage + void writeBufferFloat(ByteOrder order, long byteOffset, float value) throws UnsupportedMessageException { + throw UnsupportedMessageException.create(); + } + + @ExportMessage + void writeBufferDouble(ByteOrder order, long byteOffset, double value) throws UnsupportedMessageException { + throw UnsupportedMessageException.create(); + } +} From 37b8e02c20444bf544ab0c9eb94a07af363eac40 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 1 Aug 2024 21:51:50 +0200 Subject: [PATCH 148/265] Rename byteOffset and byteLength getter methods. --- .../truffle/js/builtins/DataViewPrototypeBuiltins.java | 8 ++++---- .../truffle/js/builtins/JSConstructTypedArrayNode.java | 2 +- .../truffle/js/builtins/TypedArrayPrototypeBuiltins.java | 8 ++++---- .../truffle/js/nodes/array/GetViewByteLengthNode.java | 4 ++-- .../truffle/js/nodes/array/TypedArrayLengthNode.java | 2 +- .../com/oracle/truffle/js/runtime/array/TypedArray.java | 4 ++-- .../truffle/js/runtime/builtins/JSArrayBufferView.java | 8 ++++---- .../js/runtime/builtins/JSArrayBufferViewBase.java | 2 +- .../oracle/truffle/js/runtime/builtins/JSDataView.java | 8 ++++---- .../truffle/js/runtime/builtins/JSDataViewObject.java | 4 ++-- .../truffle/trufflenode/serialization/Serializer.java | 6 +++--- 11 files changed, 28 insertions(+), 28 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DataViewPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DataViewPrototypeBuiltins.java index f676fb3eefc..b936b08e4e7 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DataViewPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DataViewPrototypeBuiltins.java @@ -185,12 +185,12 @@ static void checkViewOutOfBounds(JSContext context, JSDataViewObject dataView, I } if (!context.getArrayBufferNotShrunkAssumption().isValid()) { long bufferByteLength = arrayBuffer.getByteLength(); - int byteOffsetStart = dataView.getOffset(); + int byteOffsetStart = dataView.getByteOffset(); long byteOffsetEnd; if (dataView.hasAutoLength()) { byteOffsetEnd = bufferByteLength; } else { - byteOffsetEnd = byteOffsetStart + dataView.getLength(); + byteOffsetEnd = byteOffsetStart + dataView.getByteLength(); } if (byteOffsetStart > bufferByteLength || byteOffsetEnd > bufferByteLength) { errorBranch.enter(node); @@ -226,7 +226,7 @@ protected final int getBufferIndex(JSDataViewObject dataView, long getIndex, errorBranch.enter(this); throw Errors.createRangeError("index + elementSize > viewLength"); } - int viewOffset = dataView.getOffset(); + int viewOffset = dataView.getByteOffset(); assert getIndex + viewOffset <= Integer.MAX_VALUE; int bufferIndex = (int) (getIndex + viewOffset); @@ -406,7 +406,7 @@ protected final Object doDataView(JSDataViewObject dataView, return getViewByteLengthNode.execute(dataView, getContext()); case byteOffset: checkViewOutOfBounds(getContext(), dataView, errorBranch, this); - return dataView.getOffset(); + return dataView.getByteOffset(); default: throw Errors.shouldNotReachHere(); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/JSConstructTypedArrayNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/JSConstructTypedArrayNode.java index 4c21815f5d2..8bb0c40516b 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/JSConstructTypedArrayNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/JSConstructTypedArrayNode.java @@ -297,7 +297,7 @@ protected JSDynamicObject doTypedArray(JSDynamicObject newTarget, JSTypedArrayOb if (bulkCopyProfile.profile(this, !sourceType.isInterop() && sourceType.getElementType() == typedArray.getElementType())) { JSArrayBufferObject srcData = arrayBufferView.getArrayBuffer(); - int sourceByteOffset = arrayBufferView.getOffset(); + int sourceByteOffset = arrayBufferView.getByteOffset(); int elementSize = sourceType.bytesPerElement(); int sourceByteLength = (int) length * elementSize; diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java index 2e31315bf2b..89c9dbed8e2 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java @@ -329,7 +329,7 @@ protected JSTypedArrayObject subarray(JSTypedArrayObject thisObj, Object start, long srcLength = JSArrayBufferView.isOutOfBounds(thisObj, getContext()) ? 0 : array.length(thisObj); long relativeStart = toInteger(start); long startIndex = negativeBegin.profile(this, relativeStart < 0) ? Math.max(srcLength + relativeStart, 0) : Math.min(relativeStart, srcLength); - int srcByteOffset = thisObj.getOffset(); + int srcByteOffset = thisObj.getByteOffset(); long beginByteOffset = srcByteOffset + startIndex * array.bytesPerElement(); Object newLength; if (thisObj.hasAutoLength() && end == Undefined.instance) { @@ -527,8 +527,8 @@ private void setArrayBufferView(JSTypedArrayObject targetView, JSTypedArrayObjec int sourceLen = (int) sourceLength; JSArrayBufferObject sourceBuffer = JSArrayBufferView.getArrayBuffer(sourceView); JSArrayBufferObject targetBuffer = JSArrayBufferView.getArrayBuffer(targetView); - int srcByteOffset = sourceView.getOffset(); - int targetByteOffset = targetView.getOffset(); + int srcByteOffset = sourceView.getByteOffset(); + int targetByteOffset = targetView.getByteOffset(); int srcByteIndex; if (sameBufferProf.profile(sourceBuffer == targetBuffer)) { @@ -958,7 +958,7 @@ protected final int doTypedArray(JSTypedArrayObject typedArray, case byteLength: return typedArrayLengthNode.execute(this, typedArray, getContext()) << typedArray.getArrayType().bytesPerElementShift(); case byteOffset: - return typedArray.getOffset(); + return typedArray.getByteOffset(); default: throw Errors.shouldNotReachHere(); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/GetViewByteLengthNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/GetViewByteLengthNode.java index 2b66a393d7c..7aa0ed1a4bc 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/GetViewByteLengthNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/GetViewByteLengthNode.java @@ -61,7 +61,7 @@ public abstract class GetViewByteLengthNode extends JavaScriptBaseNode { @Specialization(guards = {"!isOutOfBounds(dataView, context)", "!dataView.hasAutoLength()"}) protected static int doFixedLength(JSDataViewObject dataView, JSContext context) { assert !JSDataView.isOutOfBounds(dataView, context); - return dataView.getLengthFixed(); + return dataView.getByteLengthFixed(); } @Specialization(guards = {"!isOutOfBounds(dataView, context)", "dataView.hasAutoLength()"}) @@ -70,7 +70,7 @@ protected final int doAutoLength(JSDataViewObject dataView, JSContext context, assert !JSDataView.isOutOfBounds(dataView, context); JSArrayBufferObject arrayBuffer = dataView.getArrayBuffer(); int byteLength = getByteLengthNode.execute(this, arrayBuffer, context); - int byteOffset = dataView.getOffset(); + int byteOffset = dataView.getByteOffset(); return (byteLength - byteOffset); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/TypedArrayLengthNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/TypedArrayLengthNode.java index d3c7fe6deac..828d64893f1 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/TypedArrayLengthNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/TypedArrayLengthNode.java @@ -73,7 +73,7 @@ protected static int doAutoLength(Node node, JSTypedArrayObject typedArray, JSCo assert !JSArrayBufferView.isOutOfBounds(typedArray, context); JSArrayBufferObject arrayBuffer = typedArray.getArrayBuffer(); int byteLength = getByteLengthNode.execute(node, arrayBuffer, context); - int byteOffset = typedArray.getOffset(); + int byteOffset = typedArray.getByteOffset(); return (byteLength - byteOffset) >> typedArray.getArrayType().bytesPerElementShift(); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArray.java index 94ffa33cffe..055079880e7 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/TypedArray.java @@ -40,7 +40,7 @@ */ package com.oracle.truffle.js.runtime.array; -import static com.oracle.truffle.js.runtime.builtins.JSArrayBufferView.typedArrayGetOffset; +import static com.oracle.truffle.js.runtime.builtins.JSArrayBufferView.typedArrayGetByteOffset; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -192,7 +192,7 @@ public static JSArrayBufferObject getBufferFromTypedArray(JSDynamicObject typedA public final int getOffset(JSDynamicObject object) { if (offset) { - return typedArrayGetOffset(object); + return typedArrayGetByteOffset(object); } else { return 0; } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayBufferView.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayBufferView.java index 49df8fc5900..431e2ff2d47 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayBufferView.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayBufferView.java @@ -83,8 +83,8 @@ public static int typedArrayGetLength(JSDynamicObject thisObj) { return ((JSTypedArrayObject) thisObj).getLength(); } - public static int typedArrayGetOffset(JSDynamicObject thisObj) { - return ((JSTypedArrayObject) thisObj).getOffset(); + public static int typedArrayGetByteOffset(JSDynamicObject thisObj) { + return ((JSTypedArrayObject) thisObj).getByteOffset(); } public static TruffleString typedArrayGetName(JSDynamicObject thisObj) { @@ -110,7 +110,7 @@ public static int getByteOffset(JSDynamicObject store, JSContext ctx) { if (JSArrayBufferView.isOutOfBounds((JSTypedArrayObject) store, ctx)) { return 0; } - return typedArrayGetOffset(store); + return typedArrayGetByteOffset(store); } @TruffleBoundary @@ -405,7 +405,7 @@ public static boolean isOutOfBounds(JSTypedArrayObject typedArray, JSContext ctx return false; } else { long bufferByteLength = typedArray.getArrayBuffer().getByteLength(); - int byteOffsetStart = typedArray.getOffset(); + int byteOffsetStart = typedArray.getByteOffset(); long byteOffsetEnd; if (typedArray.hasAutoLength()) { byteOffsetEnd = bufferByteLength; diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayBufferViewBase.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayBufferViewBase.java index 213f55a58a4..c38d75ba9fc 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayBufferViewBase.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayBufferViewBase.java @@ -64,7 +64,7 @@ public final JSArrayBufferObject getArrayBuffer() { return arrayBuffer; } - public final int getOffset() { + public final int getByteOffset() { return offset; } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSDataView.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSDataView.java index d71d1fea3a2..cf65d67ad67 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSDataView.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSDataView.java @@ -85,14 +85,14 @@ public static int dataViewGetByteLength(JSDataViewObject thisObj) { if (JSArrayBuffer.isDetachedBuffer(thisObj.getArrayBuffer())) { return 0; } - return thisObj.getLength(); + return thisObj.getByteLength(); } public static int dataViewGetByteOffset(JSDataViewObject thisObj) { if (JSArrayBuffer.isDetachedBuffer(thisObj.getArrayBuffer())) { return 0; } - return thisObj.getOffset(); + return thisObj.getByteOffset(); } // IsViewOutOfBounds() @@ -104,12 +104,12 @@ public static boolean isOutOfBounds(JSDataViewObject dataView, JSContext ctx) { return false; } else { long bufferByteLength = dataView.getArrayBuffer().getByteLength(); - int byteOffsetStart = dataView.getOffset(); + int byteOffsetStart = dataView.getByteOffset(); long byteOffsetEnd; if (dataView.hasAutoLength()) { byteOffsetEnd = bufferByteLength; } else { - byteOffsetEnd = byteOffsetStart + dataView.getLength(); + byteOffsetEnd = byteOffsetStart + dataView.getByteLength(); } return (byteOffsetStart > bufferByteLength || byteOffsetEnd > bufferByteLength); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSDataViewObject.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSDataViewObject.java index e1078f9577b..329efeaad7a 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSDataViewObject.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSDataViewObject.java @@ -56,12 +56,12 @@ public TruffleString getClassName() { return JSDataView.CLASS_NAME; } - public int getLengthFixed() { + public int getByteLengthFixed() { assert !hasAutoLength(); return length; } - public int getLength() { + public int getByteLength() { return hasAutoLength() ? (arrayBuffer.getByteLength() - offset) : length; } diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/Serializer.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/Serializer.java index 0cb611052e2..52af2018555 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/Serializer.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/Serializer.java @@ -510,7 +510,7 @@ private void writeJSArrayBufferView(JSTypedArrayObject view) { if (treatArrayBufferViewsAsHostObjects) { writeHostObject(view); } else { - int offset = view.getOffset(); + int offset = view.getByteOffset(); TypedArray typedArray = view.getArrayType(); int length = typedArray.lengthInt(view) * typedArray.bytesPerElement(); ArrayBufferViewTag tag = ArrayBufferViewTag.fromFactory(typedArray.getFactory()); @@ -523,8 +523,8 @@ private void writeJSDataView(JSDataViewObject view) { writeTag(SerializationTag.HOST_OBJECT); NativeAccess.writeHostObject(delegate, view); } else { - int offset = view.getOffset(); - int length = view.getLength(); + int offset = view.getByteOffset(); + int length = view.getByteLength(); writeJSArrayBufferView(ArrayBufferViewTag.DATA_VIEW, offset, length); } } From be43ace0e93d3c936da61e2f810712f1b0688dec Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 1 Aug 2024 21:58:17 +0200 Subject: [PATCH 149/265] Introduce JSTypedArrayObject.getByteLength(). --- .../oracle/truffle/js/runtime/builtins/JSArrayBufferView.java | 2 +- .../truffle/js/runtime/builtins/JSTypedArrayObject.java | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayBufferView.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayBufferView.java index 431e2ff2d47..f24db569c76 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayBufferView.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSArrayBufferView.java @@ -410,7 +410,7 @@ public static boolean isOutOfBounds(JSTypedArrayObject typedArray, JSContext ctx if (typedArray.hasAutoLength()) { byteOffsetEnd = bufferByteLength; } else { - byteOffsetEnd = byteOffsetStart + typedArray.getLength() * typedArray.getArrayType().bytesPerElement(); + byteOffsetEnd = byteOffsetStart + typedArray.getByteLength(); } return (byteOffsetStart > bufferByteLength || byteOffsetEnd > bufferByteLength); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java index 56bf42445dc..2970b16d542 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTypedArrayObject.java @@ -89,6 +89,10 @@ public int getLength() { return hasAutoLength() ? (arrayBuffer.getByteLength() - offset) >> arrayType.bytesPerElementShift() : length; } + public int getByteLength() { + return hasAutoLength() ? (arrayBuffer.getByteLength() - offset) : (length << arrayType.bytesPerElementShift()); + } + public static JSTypedArrayObject create(Shape shape, JSDynamicObject proto, TypedArray arrayType, JSArrayBufferObject arrayBuffer, int length, int offset) { return new JSTypedArrayObject(shape, proto, arrayType, arrayBuffer, length, offset); } From 4a80e99b2d5432c3467217f7facef73a1e530f08 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Fri, 2 Aug 2024 13:41:33 +0200 Subject: [PATCH 150/265] Make wasm and other languages available in the `js` launcher by default (no longer requires --polyglot). --- .../src/com/oracle/truffle/js/shell/JSLauncher.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/graal-js/src/com.oracle.truffle.js.shell/src/com/oracle/truffle/js/shell/JSLauncher.java b/graal-js/src/com.oracle.truffle.js.shell/src/com/oracle/truffle/js/shell/JSLauncher.java index bbf7dbc571f..ec1b2c678ee 100644 --- a/graal-js/src/com.oracle.truffle.js.shell/src/com/oracle/truffle/js/shell/JSLauncher.java +++ b/graal-js/src/com.oracle.truffle.js.shell/src/com/oracle/truffle/js/shell/JSLauncher.java @@ -102,6 +102,11 @@ protected String getLanguageId() { return "js"; } + @Override + protected String[] getDefaultLanguages() { + return new String[0]; + } + protected void preEval(@SuppressWarnings("unused") Context context) { } From df589a3d9e6e2378f4fe39a195cb67720dabe4d8 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Fri, 2 Aug 2024 13:36:59 +0200 Subject: [PATCH 151/265] Add WebAssembly smoke test for js standalone. --- graal-js/ci.jsonnet | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/graal-js/ci.jsonnet b/graal-js/ci.jsonnet index d5226e1da49..6d6bac816fa 100644 --- a/graal-js/ci.jsonnet +++ b/graal-js/ci.jsonnet @@ -37,7 +37,7 @@ local ci = import '../ci.jsonnet'; }, local nativeImageSmokeTest = checkoutJsBenchmarks + { - suiteimports+:: ['vm', 'substratevm'], + suiteimports+:: ['vm', 'substratevm', 'wasm'], nativeimages+:: ['lib:jsvm', 'lib:jvmcicompiler'], extraimagebuilderarguments+:: ['-H:+ReportExceptionStackTraces'], run+: [ @@ -49,9 +49,11 @@ local ci = import '../ci.jsonnet'; ['set-export', 'STANDALONE_HOME', ['mx', '--quiet', 'standalone-home', 'js', '--type=native']], ['${STANDALONE_HOME}/bin/js', '--native', '-e', "print('hello:' + Array.from(new Array(10), (x,i) => i*i ).join('|'))"], ['${STANDALONE_HOME}/bin/js', '--native', '../../js-benchmarks/harness.js', '--', '../../js-benchmarks/octane-richards.js', '--show-warmup'], + ['${STANDALONE_HOME}/bin/js', '--experimental-options', '--js.webassembly', '-e', 'new WebAssembly.Module(new Uint8Array([0x00,0x61,0x73,0x6d,0x01,0x00,0x00,0x00]))'], ['set-export', 'STANDALONE_HOME', ['mx', '--quiet', 'standalone-home', 'js', '--type=jvm']], ['${STANDALONE_HOME}/bin/js', '--jvm', '-e', "print('hello:' + Array.from(new Array(10), (x,i) => i*i ).join('|'))"], ['${STANDALONE_HOME}/bin/js', '--jvm', '../../js-benchmarks/harness.js', '--', '../../js-benchmarks/octane-richards.js', '--show-warmup'], + ['${STANDALONE_HOME}/bin/js', '--experimental-options', '--js.webassembly', '-e', 'new WebAssembly.Module(new Uint8Array([0x00,0x61,0x73,0x6d,0x01,0x00,0x00,0x00]))'], # maven-downloader smoke test ['VERBOSE_GRAALVM_LAUNCHERS=true', '${STANDALONE_HOME}/bin/js-polyglot-get', '-o', 'maven downloader output', '-a', 'wasm', '-v', '23.1.3'], ], From 3c5528977a4e2479b5cb6294df10d83b70b15c62 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Sun, 4 Aug 2024 14:26:57 +0200 Subject: [PATCH 152/265] Do not use blockwise splice when the new length exceeds Integer.MAX_VALUE. --- .../truffle/js/builtins/ArrayPrototypeBuiltins.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java index 5bf8883835f..ec82c8d1cf6 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java @@ -2031,7 +2031,7 @@ static void doCached(JSDynamicObject array, long len, long actualStart, long act @Bind("this") Node node, @Cached @Shared GetPrototypeNode getPrototypeNode, @Cached @Shared InlinedConditionProfile arrayElementwise) { - if (arrayElementwise.profile(node, parent.mustUseElementwise(array, len, cachedArrayType.cast(arrayType), getPrototypeNode))) { + if (arrayElementwise.profile(node, parent.mustUseElementwise(array, len, actualDeleteCount, itemCount, cachedArrayType.cast(arrayType), getPrototypeNode))) { parent.spliceJSArrayElementwise(array, len, actualStart, actualDeleteCount, itemCount); } else { parent.spliceJSArrayBlockwise(array, actualStart, actualDeleteCount, itemCount, cachedArrayType.cast(arrayType)); @@ -2043,7 +2043,7 @@ static void doUncached(JSDynamicObject array, long len, long actualStart, long a @Bind("this") Node node, @Cached @Shared GetPrototypeNode getPrototypeNode, @Cached @Shared InlinedConditionProfile arrayElementwise) { - if (arrayElementwise.profile(node, parent.mustUseElementwise(array, len, arrayType, getPrototypeNode))) { + if (arrayElementwise.profile(node, parent.mustUseElementwise(array, len, actualDeleteCount, itemCount, arrayType, getPrototypeNode))) { parent.spliceJSArrayElementwise(array, len, actualStart, actualDeleteCount, itemCount); } else { parent.spliceJSArrayBlockwise(array, actualStart, actualDeleteCount, itemCount, arrayType); @@ -2051,13 +2051,14 @@ static void doUncached(JSDynamicObject array, long len, long actualStart, long a } } - final boolean mustUseElementwise(JSDynamicObject obj, long expectedLength, ScriptArray array, GetPrototypeNode getPrototypeNode) { + final boolean mustUseElementwise(JSDynamicObject obj, long expectedLength, long deleteCount, long itemCount, ScriptArray array, GetPrototypeNode getPrototypeNode) { return array instanceof SparseArray || array.isLengthNotWritable() || getPrototypeNode.execute(obj) != getRealm().getArrayPrototype() || !getContext().getArrayPrototypeNoElementsAssumption().isValid() || (!getContext().getFastArrayAssumption().isValid() && JSSlowArray.isJSSlowArray(obj)) || - array.length(obj) != expectedLength; + array.length(obj) != expectedLength || + expectedLength + itemCount - deleteCount >= Integer.MAX_VALUE; } private void spliceRead(Object thisObj, long actualStart, long actualDeleteCount, Object aObj, long length) { From da1477fb1ec91b5832d2eb87ec5fbb0841111e62 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Sun, 4 Aug 2024 14:47:29 +0200 Subject: [PATCH 153/265] Testing the grow of an array length over Integer.MAX_VALUE (during Array.prototype.splice). --- .../com.oracle.truffle.js.test/js/GR-56689.js | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 graal-js/src/com.oracle.truffle.js.test/js/GR-56689.js diff --git a/graal-js/src/com.oracle.truffle.js.test/js/GR-56689.js b/graal-js/src/com.oracle.truffle.js.test/js/GR-56689.js new file mode 100644 index 00000000000..875cf0243a1 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/js/GR-56689.js @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ + +/** + * Regression test of the grow of an array length over Integer.MAX_VALUE (during Array.prototype.splice). + */ + +load("assert.js"); + +var array = Array(2147483647); +assertSameContent([], array.splice(0, 0, 'newElement')); +assertSame('newElement', array[0]); +assertSame(2147483648, array.length); +assertFalse(1 in array); +assertFalse(2147483647 in array); + +// Original test-case from the fuzzer + +Array(2147483647)["splice"](255, 0, "splice"); \ No newline at end of file From eeeac55ef8e844536f08bcfd1eded3fbf0a300d2 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 2 Aug 2024 21:05:08 +0000 Subject: [PATCH 154/265] Update graal import. --- graal-js/mx.graal-js/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/mx.graal-js/suite.py b/graal-js/mx.graal-js/suite.py index ad023b30ca6..bc2ffbbdeca 100644 --- a/graal-js/mx.graal-js/suite.py +++ b/graal-js/mx.graal-js/suite.py @@ -24,7 +24,7 @@ { "name" : "regex", "subdir" : True, - "version" : "4e556c114c931e03795824268585286ea32f86cc", + "version" : "98b753e57296b85398539fe425cf4526f9e56b20", "urls" : [ {"url" : "https://github.com/oracle/graal.git", "kind" : "git"}, ] From 157fc1cb32d85ff88e93f39ec8cd33aac962360e Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 2 Aug 2024 21:05:09 +0000 Subject: [PATCH 155/265] Sync CI files. --- common.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/common.json b/common.json index 83df74ca1ca..cc2e25f736f 100644 --- a/common.json +++ b/common.json @@ -45,13 +45,13 @@ "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.2+13-jvmci-23.1-b33-sulong", "platformspecific": true }, "graalvm-ee-21": {"name": "graalvm-java21", "version": "23.1.3", "platformspecific": true }, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+7", "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+7-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+7-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+7-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+7-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+7-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+7-jvmci-b01-sulong", "platformspecific": true } + "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+8", "platformspecific": true, "extrabundles": ["static-libs"]}, + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+8-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+8-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+8-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+8-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+8-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+8-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { From c916a6f1a630c1db1ed16f57a59a8c4e5e0b196e Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Sun, 4 Aug 2024 17:24:13 +0200 Subject: [PATCH 156/265] Avoiding a potential ArrayIndexOutOfBoundsException in addRangeGrow(). --- .../truffle/js/runtime/array/dyn/AbstractWritableArray.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractWritableArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractWritableArray.java index a2acd5a57bc..0391335f32b 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractWritableArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractWritableArray.java @@ -691,8 +691,8 @@ ScriptArray addRangeImplContiguous(JSDynamicObject object, long offset, int size private ScriptArray addRangeGrow(JSDynamicObject object, Object array, int arrayLength, int usedLength, int length, int offset, int size, int arrayOffset, long indexOffset) { Object newArray = allocateArray(nextPower(arrayLength + size)); - if (offset >= arrayLength) { - System.arraycopy(array, arrayOffset, newArray, arrayOffset, arrayLength - arrayOffset); + if (offset >= arrayOffset + usedLength) { + System.arraycopy(array, arrayOffset, newArray, arrayOffset, usedLength); fillWithHoles(newArray, arrayOffset + usedLength, arrayOffset + usedLength + size); return ensureHolesArray(object, length + size, newArray, indexOffset, arrayOffset, usedLength + size, arrayGetHoleCount(object) + size); } else { From 4cd2320ee2afb4bba85fb10b4bfec0d30a248948 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Sun, 4 Aug 2024 17:28:46 +0200 Subject: [PATCH 157/265] Regression test of a potential ArrayIndexOutOfBoundsException in addRangeGrow(). --- .../com.oracle.truffle.js.test/js/GR-56531.js | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 graal-js/src/com.oracle.truffle.js.test/js/GR-56531.js diff --git a/graal-js/src/com.oracle.truffle.js.test/js/GR-56531.js b/graal-js/src/com.oracle.truffle.js.test/js/GR-56531.js new file mode 100644 index 00000000000..4b933b60e97 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/js/GR-56531.js @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ + +load("assert.js"); + +var array = [42,,211]; +array.length = 2; +assertSameContent([], array.splice(2, 0, 1, 2, 3)); +assertSameContent([42,,1,2,3], array); + +// Original test-case from the fuzzer + +const v2 = [-361.1425116275642]; +v2[2] = 2.0; +v2.length = 2; +v2.splice(113, 113, 113, [-65537,-2147483648,8], 113); From 3b2c1145eeb4f8bfbe2842ddcfd46c69679b1049 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Sun, 4 Aug 2024 17:22:44 +0200 Subject: [PATCH 158/265] Revert js launcher default languages to js only, but include wasm if --webassembly flag is set. Fixes running `js` with --engine.SpawnIsolates=true. --- .../oracle/truffle/js/shell/JSLauncher.java | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js.shell/src/com/oracle/truffle/js/shell/JSLauncher.java b/graal-js/src/com.oracle.truffle.js.shell/src/com/oracle/truffle/js/shell/JSLauncher.java index ec1b2c678ee..5daeb88cd8b 100644 --- a/graal-js/src/com.oracle.truffle.js.shell/src/com/oracle/truffle/js/shell/JSLauncher.java +++ b/graal-js/src/com.oracle.truffle.js.shell/src/com/oracle/truffle/js/shell/JSLauncher.java @@ -46,6 +46,7 @@ import java.io.File; import java.io.IOException; +import java.io.OutputStream; import java.io.PrintStream; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -69,6 +70,7 @@ public class JSLauncher extends AbstractLanguageLauncher { static final String MODULE_MIME_TYPE = "application/javascript+module"; + private static final String WASM_LANGUAGE_ID = "wasm"; private static final String PROMPT = "> "; public static void main(String[] args) { @@ -79,6 +81,7 @@ public static void main(String[] args) { private boolean fuzzilliREPRL = false; private boolean allowExperimentalOptions = false; private boolean useSharedEngine = false; + private boolean wasmEnabled = false; private String[] programArgs; private final List unparsedSources = new LinkedList<>(); private VersionAction versionAction = VersionAction.None; @@ -104,7 +107,11 @@ protected String getLanguageId() { @Override protected String[] getDefaultLanguages() { - return new String[0]; + if (wasmEnabled && isLanguageAvailable(WASM_LANGUAGE_ID)) { + return new String[]{getLanguageId(), WASM_LANGUAGE_ID}; + } else { + return super.getDefaultLanguages(); + } } protected void preEval(@SuppressWarnings("unused") Context context) { @@ -146,7 +153,8 @@ protected List preprocessArguments(List arguments, Map 0) { + boolean hasEquals = equalsIndex > 0; + if (hasEquals) { value = flag.substring(equalsIndex + 1); flag = flag.substring(0, equalsIndex); } else if (iterator.hasNext()) { @@ -162,8 +170,12 @@ protected List preprocessArguments(List arguments, Map Date: Mon, 5 Aug 2024 10:19:05 +0200 Subject: [PATCH 159/265] Array length may not fit into int in SetArrayLengthOrDeleteNode. --- .../src/com/oracle/truffle/js/nodes/array/ArrayLengthNode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/ArrayLengthNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/ArrayLengthNode.java index 6e328c75b95..935fe06a683 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/ArrayLengthNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/array/ArrayLengthNode.java @@ -236,7 +236,7 @@ protected void doGeneric(JSDynamicObject arrayObj, int length, private void deleteAndSetLength(JSDynamicObject arrayObj, int length, ScriptArray arrayType, Node node, ScriptArray.SetLengthProfileAccess setLengthProfile) { ScriptArray array = arrayType; - for (int i = array.lengthInt(arrayObj) - 1; i >= length; i--) { + for (long i = array.length(arrayObj) - 1; i >= length; i--) { if (array.canDeleteElement(arrayObj, i, strict)) { array = array.deleteElement(arrayObj, i, strict); arraySetArrayType(arrayObj, array); From e9a1fbbfb2dd2d4c5b19de3164c2bfab2e7f8b43 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Mon, 5 Aug 2024 10:30:39 +0200 Subject: [PATCH 160/265] Testing pop() on a frozen array of length 2147483648. --- .../com.oracle.truffle.js.test/js/GR-56529.js | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 graal-js/src/com.oracle.truffle.js.test/js/GR-56529.js diff --git a/graal-js/src/com.oracle.truffle.js.test/js/GR-56529.js b/graal-js/src/com.oracle.truffle.js.test/js/GR-56529.js new file mode 100644 index 00000000000..7dbbd037317 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/js/GR-56529.js @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ + +load("assert.js"); + +let array = Object.freeze(new Array(2147483648)); +assertThrows(() => { + array.pop(); +}, TypeError); + +// Original test-case from the fuzzer + +const v1 = [-60891989,1,260564070,4294967296,10030]; +v1[2147483647] %= 1607265652; +assertThrows(() => { + Object.freeze(v1).pop(); +}, TypeError); From 94494fd28d8ab8826ff4e9d6da4c86d2457950ce Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Tue, 6 Aug 2024 13:20:46 +0200 Subject: [PATCH 161/265] Do not use BigDecimal when comparing a huge BigInt and a Number. --- .../src/com/oracle/truffle/js/runtime/BigInt.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/BigInt.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/BigInt.java index b891f6218ab..31a81b6fe2c 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/BigInt.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/BigInt.java @@ -213,9 +213,14 @@ public int compareValueTo(double b) { } else if (b == Double.NEGATIVE_INFINITY) { return 1; } else { - BigDecimal thisValue = new BigDecimal(value); - BigDecimal theOtherValue = new BigDecimal(b); - return thisValue.compareTo(theOtherValue); + if (value.bitLength() > 1024) { + // value uses more bits than can fit into double + return value.signum(); + } else { + BigDecimal thisValue = new BigDecimal(value); + BigDecimal theOtherValue = new BigDecimal(b); + return thisValue.compareTo(theOtherValue); + } } } From 84e05c8754aca2f4604d2885b83afc0125a13589 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Tue, 6 Aug 2024 13:37:28 +0200 Subject: [PATCH 162/265] Testing the comparisons involving huge BigInts. --- .../com.oracle.truffle.js.test/js/GR-56690.js | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 graal-js/src/com.oracle.truffle.js.test/js/GR-56690.js diff --git a/graal-js/src/com.oracle.truffle.js.test/js/GR-56690.js b/graal-js/src/com.oracle.truffle.js.test/js/GR-56690.js new file mode 100644 index 00000000000..8f91f581bcc --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/js/GR-56690.js @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ + +/** + * Regression test of the comparisons involving huge BigInts. + */ + +load("assert.js"); + +const hugePositive = 2n**2000000000n; +const hugeNegative = -hugePositive; +const number = 42.211; + +assertFalse(hugePositive < number); +assertTrue(number < hugePositive); +assertTrue(hugeNegative < number); +assertFalse(number < hugeNegative); + +assertTrue(hugePositive > number); +assertFalse(number > hugePositive); +assertFalse(hugeNegative > number); +assertTrue(number > hugeNegative); + +assertFalse(hugePositive <= number); +assertTrue(number <= hugePositive); +assertTrue(hugeNegative <= number); +assertFalse(number <= hugeNegative); + +assertTrue(hugePositive >= number); +assertFalse(number >= hugePositive); +assertFalse(hugeNegative >= number); +assertTrue(number >= hugeNegative); + +// Original test-case from the fuzzer + +let v1 = 5n; +const o6 = { + p(a3) { + return v1 < 1.9255255399849514; + }, +}; +v1 >>= -1825025338n; +o6["p"](); From 4fa302cc596c70e8a9258972212b9f951fa900fe Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 5 Aug 2024 16:32:24 +0200 Subject: [PATCH 163/265] Update component lists for benchmark env files. --- graal-js/mx.graal-js/mx_graal_js_benchmark.py | 6 +++--- graal-nodejs/mx.graal-nodejs/mx_graal_nodejs_benchmark.py | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/graal-js/mx.graal-js/mx_graal_js_benchmark.py b/graal-js/mx.graal-js/mx_graal_js_benchmark.py index ba337374405..b664b848ca0 100644 --- a/graal-js/mx.graal-js/mx_graal_js_benchmark.py +++ b/graal-js/mx.graal-js/mx_graal_js_benchmark.py @@ -1,7 +1,7 @@ # # ---------------------------------------------------------------------------------------------------- # -# Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -105,10 +105,10 @@ def subgroup(self): add_bm_suite(JMHDistGraalJsBenchmarkSuite()) # --env ce-js-bench -ce_components = ['cmp', 'gvm', 'icu4j', 'js', 'jsl', 'jss', 'lg', 'rgx', 'sdk', 'sdkc', 'sdkl', 'sdkni', 'svm', 'svmsl', 'svmt', 'tfl', 'tfla', 'tflc', 'tflm', 'tflsm'] +ce_components = ['cmp', 'gvm', 'icu4j', 'js', 'jsl', 'jss', 'lg', 'rgx', 'sdk', 'sdkc', 'sdkl', 'sdkni', 'svm', 'svmsl', 'svmt', 'tfl', 'tfla', 'tflc', 'tflm', 'tflsm', 'xz'] # --env ee-js-bench -ee_components = ['cmp', 'cmpee', 'gvm', 'icu4j', 'js', 'jsl', 'jss', 'lg', 'rgx', 'sdk', 'sdkc', 'sdkl', 'sdkni', 'svm', 'svmee', 'svmeegc', 'svmsl', 'svmt', 'svmte', 'tfl', 'tfla', 'tflc', 'tfle', 'tflllm', 'tflm', 'tflsm'] +ee_components = ['cmp', 'cmpee', 'gvm', 'icu4j', 'js', 'jsl', 'jss', 'lg', 'rgx', 'sdk', 'sdkc', 'sdkl', 'sdkni', 'svm', 'svmee', 'svmeegc', 'svmsl', 'svmt', 'svmte', 'tfl', 'tfla', 'tflc', 'tfle', 'tflllm', 'tflm', 'tflsm', 'xz'] # svmeegc is only available on linux if not mx.is_linux(): ee_components.remove('svmeegc') diff --git a/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs_benchmark.py b/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs_benchmark.py index c2c6ae22b08..5f24d542054 100644 --- a/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs_benchmark.py +++ b/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs_benchmark.py @@ -1,7 +1,7 @@ # # ---------------------------------------------------------------------------------------------------- # -# Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2007, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -70,10 +70,11 @@ def register_nodejs_vms(): mx_nodejs_benchmarks.add_vm(GraalNodeJsVm('default', []), _suite, 10) # --env ce-nodejs-bench -ce_components = ['cmp', 'gvm', 'icu4j', 'js', 'jsl', 'jss', 'lg', 'libpoly', 'njs', 'njsl', 'rgx', 'sdk', 'sdkc', 'sdkl', 'sdkni', 'sjsvm', 'spolyglot', 'svm', 'svmsl', 'svmt', 'tfl', 'tfla', 'tflc', 'tflm', 'tflsm'] +ce_components = ['cmp', 'gvm', 'icu4j', 'js', 'jsl', 'jss', 'lg', 'libpoly', 'njs', 'njsl', 'rgx', 'sdk', 'sdkc', 'sdkl', 'sdkni', 'sjsvm', 'spolyglot', 'svm', 'svmsl', 'svmt', 'tfl', 'tfla', 'tflc', 'tflm', 'tflsm', 'xz'] + # --env ee-nodejs-bench -ee_components = ['cmp', 'cmpee', 'gvm', 'icu4j', 'js', 'jsl', 'jss', 'lg', 'libpoly', 'njs', 'njsl', 'rgx', 'sdk', 'sdkc', 'sdkl', 'sdkni', 'sjsvm', 'spolyglot', 'svm', 'svmee', 'svmeegc', 'svmsl', 'svmt', 'svmte', 'tfl', 'tfla', 'tflc', 'tfle', 'tflllm', 'tflm', 'tflsm'] +ee_components = ['cmp', 'cmpee', 'gvm', 'icu4j', 'js', 'jsl', 'jss', 'lg', 'libpoly', 'njs', 'njsl', 'rgx', 'sdk', 'sdkc', 'sdkl', 'sdkni', 'sjsvm', 'spolyglot', 'svm', 'svmee', 'svmeegc', 'svmsl', 'svmt', 'svmte', 'tfl', 'tfla', 'tflc', 'tfle', 'tflllm', 'tflm', 'tflsm', 'xz'] # svmeegc is only available on linux if not mx.is_linux(): ee_components.remove('svmeegc') From 8ed7ca7d5409a37cdeff16a453c21180140b69da Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Thu, 8 Aug 2024 16:58:02 +0200 Subject: [PATCH 164/265] Do not add empty space at the end when an array element is inserted at the beginning. --- .../truffle/js/runtime/array/dyn/AbstractWritableArray.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractWritableArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractWritableArray.java index 0391335f32b..e0f15f04bae 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractWritableArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractWritableArray.java @@ -261,10 +261,6 @@ private int ensureCapacity(JSDynamicObject object, int internalIndex, long index int offset = 0; if (internalIndex < 0) { offset = (int) newCapacity - capacity; - // alignment to zero index - if (indexOffset < offset) { - offset = (int) indexOffset; - } } resizeArray(object, (int) newCapacity, capacity, offset); return offset; From 6807c79fa615998c1a0589e3c5bd0c71129fc652 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Thu, 8 Aug 2024 16:59:12 +0200 Subject: [PATCH 165/265] Testing the growing of an array (using splice) from the beginning. --- .../com.oracle.truffle.js.test/js/GR-57179.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 graal-js/src/com.oracle.truffle.js.test/js/GR-57179.js diff --git a/graal-js/src/com.oracle.truffle.js.test/js/GR-57179.js b/graal-js/src/com.oracle.truffle.js.test/js/GR-57179.js new file mode 100644 index 00000000000..9740d67cbfd --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/js/GR-57179.js @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ + +load("assert.js"); + +var array = [,-1]; +for (var i = 1; i <= 1000; i++) { + array.splice(0,0,i); +} + +assertSame(1002, array.length); +for (var i = 0; i < array.length; i++) { + var expected = (i === 1000) ? undefined : (1000 - i); + assertSame(expected, array[i]); +} From f3ce03a2ed4c3393daa7a333c6115fa8e55b7e27 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Fri, 9 Aug 2024 14:31:48 +0200 Subject: [PATCH 166/265] Adoption of the internal array by zero-based array needs 0 index offset. --- .../com/oracle/truffle/js/nodes/access/WriteElementNode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/WriteElementNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/WriteElementNode.java index 4f66cd80498..fbfe3728a96 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/WriteElementNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/WriteElementNode.java @@ -942,7 +942,7 @@ private boolean doIntArrayWithIntValue(JSDynamicObject target, AbstractIntArray } private static boolean mightTransferToNonContiguous(AbstractIntArray intArray, JSDynamicObject target, long index) { - return intArray instanceof ContiguousIntArray && index == 0 && intArray.firstElementIndex(target) == 1; + return intArray instanceof ContiguousIntArray && index == 0 && intArray.firstElementIndex(target) == 1 && JSAbstractArray.arrayGetIndexOffset(target) == 0; } } From 308e6f20dffcd6f4a772511fe561419672f1b132 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Fri, 9 Aug 2024 14:32:16 +0200 Subject: [PATCH 167/265] Regression test of an incorrect transition to zero-based array --- graal-js/src/com.oracle.truffle.js.test/js/GR-57179.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/graal-js/src/com.oracle.truffle.js.test/js/GR-57179.js b/graal-js/src/com.oracle.truffle.js.test/js/GR-57179.js index 9740d67cbfd..40cbe652c13 100644 --- a/graal-js/src/com.oracle.truffle.js.test/js/GR-57179.js +++ b/graal-js/src/com.oracle.truffle.js.test/js/GR-57179.js @@ -17,3 +17,10 @@ for (var i = 0; i < array.length; i++) { var expected = (i === 1000) ? undefined : (1000 - i); assertSame(expected, array[i]); } + +// Regression test of an incorrect transition to zero-based array +array = []; +for (var i = 8; i >= 0; i--) { + array[i] = i; +} +assertSameContent([0,1,2,3,4,5,6,7,8], array); From ed7905b54e469eb83bb418f0ed2f5a882eaefd26 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 9 Aug 2024 21:05:34 +0000 Subject: [PATCH 168/265] Update graal import. --- graal-js/mx.graal-js/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/mx.graal-js/suite.py b/graal-js/mx.graal-js/suite.py index bc2ffbbdeca..08213fe6a29 100644 --- a/graal-js/mx.graal-js/suite.py +++ b/graal-js/mx.graal-js/suite.py @@ -24,7 +24,7 @@ { "name" : "regex", "subdir" : True, - "version" : "98b753e57296b85398539fe425cf4526f9e56b20", + "version" : "a55537477744db396e66e321edca77ab26dbaa9c", "urls" : [ {"url" : "https://github.com/oracle/graal.git", "kind" : "git"}, ] From 4c6dc8ccb085ee605e9df29f62cf229c3c3add43 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 9 Aug 2024 21:05:36 +0000 Subject: [PATCH 169/265] Sync CI files. --- common.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/common.json b/common.json index cc2e25f736f..7aa08491fe3 100644 --- a/common.json +++ b/common.json @@ -8,7 +8,7 @@ "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { - "galahad-jdk": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+6-612", "platformspecific": true, "extrabundles": ["static-libs"]}, + "galahad-jdk": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+9-885", "platformspecific": true, "extrabundles": ["static-libs"]}, "oraclejdk11": {"name": "jpg-jdk", "version": "11.0.11", "build_id": "jdk-11.0.11+9", "platformspecific": true, "extrabundles": ["static-libs"] }, @@ -45,13 +45,13 @@ "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.2+13-jvmci-23.1-b33-sulong", "platformspecific": true }, "graalvm-ee-21": {"name": "graalvm-java21", "version": "23.1.3", "platformspecific": true }, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+8", "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+8-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+8-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+8-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+8-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+8-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+8-jvmci-b01-sulong", "platformspecific": true } + "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+10", "platformspecific": true, "extrabundles": ["static-libs"]}, + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+10-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+10-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+10-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+10-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+10-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+10-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { From fe82bfebf81ace474661bd6248ebfaa3dfec2d62 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Sat, 10 Aug 2024 02:17:41 +0200 Subject: [PATCH 170/265] Fix InteropBufferView bounds check. --- .../oracle/truffle/js/runtime/interop/InteropBufferView.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/interop/InteropBufferView.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/interop/InteropBufferView.java index 16f58608667..2adc9c3f612 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/interop/InteropBufferView.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/interop/InteropBufferView.java @@ -68,6 +68,8 @@ public final class InteropBufferView implements TruffleObject { final JSTypedArrayObject arrayView; public InteropBufferView(JSArrayBufferObject arrayBuffer, int byteOffset, int byteLength, JSTypedArrayObject arrayView) { + assert byteOffset >= 0 : byteOffset; + assert byteLength >= 0 : byteLength; this.viewByteOffset = byteOffset; this.viewByteLength = byteLength; this.arrayBuffer = arrayBuffer; @@ -88,7 +90,7 @@ public long getBufferSize() { private long checkFromIndexSize(long fromIndex, int size) throws InvalidBufferOffsetException { long bufferByteOffset = viewByteOffset + fromIndex; long bufferByteLength = viewByteLength; - if ((bufferByteLength | bufferByteOffset | size) < 0 || size > bufferByteLength - bufferByteOffset) { + if ((fromIndex | size) < 0 || size > bufferByteLength - fromIndex) { throw InvalidBufferOffsetException.create(fromIndex, size); } return bufferByteOffset; From 1bc1d016940731e1230d8f7d7dfdaa853ddf7f23 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 12 Aug 2024 20:32:30 +0200 Subject: [PATCH 171/265] Strip whitespace at the start and end of test262 "includes" (and other) lists. --- .../com/oracle/truffle/js/test/external/suite/TestRunnable.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/suite/TestRunnable.java b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/suite/TestRunnable.java index fac02822026..f6d188bb0a4 100644 --- a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/suite/TestRunnable.java +++ b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/suite/TestRunnable.java @@ -198,7 +198,7 @@ protected static Stream getStrings(List scriptCode, String prefi if (line.contains(prefix)) { Matcher matcher = findPattern.matcher(line); if (matcher.find()) { - stream = Stream.concat(stream, splitPattern.splitAsStream(matcher.group(1))); + stream = Stream.concat(stream, splitPattern.splitAsStream(matcher.group(1).trim())); } } } From 287add486f893aaffd43d73713ee2eadf698fc24 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 12 Aug 2024 19:44:21 +0200 Subject: [PATCH 172/265] Bump test262 revision. --- graal-js/mx.graal-js/mx_graal_js.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/mx.graal-js/mx_graal_js.py b/graal-js/mx.graal-js/mx_graal_js.py index ac2964d7c21..11e9f8c3270 100644 --- a/graal-js/mx.graal-js/mx_graal_js.py +++ b/graal-js/mx.graal-js/mx_graal_js.py @@ -47,7 +47,7 @@ TEST262_REPO = "https://" + "github.com/tc39/test262.git" # Git revision of Test262 to checkout -TEST262_REV = "a15874163e6a4f19ee7cd3e47592af382af0f5fd" +TEST262_REV = "bcb42e339dbac06f2f9902046b1fbf62562e0cd3" # Git repository of V8 TESTV8_REPO = "https://" + "github.com/v8/v8.git" From 156caf51afd0fcb5acbc60015e50b500340f27c7 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 12 Aug 2024 20:20:21 +0200 Subject: [PATCH 173/265] Update the list of unsupported test262 features. --- .../truffle/js/test/external/test262/Test262Runnable.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java index d37482d7b61..bd7b9b696db 100644 --- a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java +++ b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java @@ -263,11 +263,17 @@ public class Test262Runnable extends TestRunnable { "well-formed-json-stringify", }); private static final Set UNSUPPORTED_FEATURES = featureSet(new String[]{ + "Atomics.pause", "Intl.DurationFormat", "IsHTMLDDA", + "Math.sumPrecise", + "RegExp.escape", "explicit-resource-management", "regexp-modifiers", + "source-phase-imports", + "source-phase-imports-module-source", "tail-call-optimization", + "uint8array-base64", }); private static final Set STAGING_FEATURES = featureSet(new String[]{ "Array.fromAsync", From 4aa6df61f4470ccfee6624426ddaea42e99584af Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 12 Aug 2024 20:36:16 +0200 Subject: [PATCH 174/265] Updating the status of test262. --- graal-js/test/test262.json | 2154 ++++++++++-------------------------- 1 file changed, 565 insertions(+), 1589 deletions(-) diff --git a/graal-js/test/test262.json b/graal-js/test/test262.json index c761d299224..26dccd3a58a 100644 --- a/graal-js/test/test262.json +++ b/graal-js/test/test262.json @@ -1996,14 +1996,6 @@ "filePath" : "built-ins/Temporal/Duration/compare/relativeto-propertybag-invalid-offset-string.js", "status" : "FAIL", "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/Duration/compare/relativeto-propertybag-out-of-range-backward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/Duration/compare/relativeto-propertybag-out-of-range-forward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" }, { "filePath" : "built-ins/Temporal/Duration/compare/relativeto-string-zoneddatetime-wrong-offset.js", "status" : "FAIL", @@ -2016,30 +2008,6 @@ "filePath" : "built-ins/Temporal/Duration/out-of-range.js", "status" : "FAIL", "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/add/relativeto-propertybag-invalid-offset-string.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/add/relativeto-propertybag-out-of-range-backward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/add/relativeto-propertybag-out-of-range-forward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/add/relativeto-string-datetime.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/add/relativeto-string-zoneddatetime-wrong-offset.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/add/relativeto-sub-minute-offset.js", - "status" : "FAIL", - "comment" : "Temporal failures" }, { "filePath" : "built-ins/Temporal/Duration/prototype/round/out-of-range-when-converting-from-normalized-duration.js", "status" : "FAIL", @@ -2048,14 +2016,6 @@ "filePath" : "built-ins/Temporal/Duration/prototype/round/relativeto-propertybag-invalid-offset-string.js", "status" : "FAIL", "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/relativeto-propertybag-out-of-range-backward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/round/relativeto-propertybag-out-of-range-forward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" }, { "filePath" : "built-ins/Temporal/Duration/prototype/round/relativeto-string-datetime.js", "status" : "FAIL", @@ -2068,42 +2028,10 @@ "filePath" : "built-ins/Temporal/Duration/prototype/round/relativeto-sub-minute-offset.js", "status" : "FAIL", "comment" : "Temporal failures" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/subtract/relativeto-propertybag-invalid-offset-string.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/subtract/relativeto-propertybag-out-of-range-backward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/subtract/relativeto-propertybag-out-of-range-forward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/subtract/relativeto-string-datetime.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/subtract/relativeto-string-zoneddatetime-wrong-offset.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/subtract/relativeto-sub-minute-offset.js", - "status" : "FAIL", - "comment" : "Temporal failures" }, { "filePath" : "built-ins/Temporal/Duration/prototype/total/relativeto-propertybag-invalid-offset-string.js", "status" : "FAIL", "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/total/relativeto-propertybag-out-of-range-backward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/Duration/prototype/total/relativeto-propertybag-out-of-range-forward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" }, { "filePath" : "built-ins/Temporal/Duration/prototype/total/relativeto-string-datetime.js", "status" : "FAIL", @@ -2120,6 +2048,10 @@ "filePath" : "built-ins/Temporal/Instant/compare/argument-string-date-with-utc-offset.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" + }, { + "filePath" : "built-ins/Temporal/Instant/compare/argument-string-minus-sign.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "built-ins/Temporal/Instant/compare/argument-string-multiple-time-zone.js", "status" : "FAIL", @@ -2132,6 +2064,10 @@ "filePath" : "built-ins/Temporal/Instant/from/argument-string-date-with-utc-offset.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" + }, { + "filePath" : "built-ins/Temporal/Instant/from/argument-string-minus-sign.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "built-ins/Temporal/Instant/from/argument-string-multiple-time-zone.js", "status" : "FAIL", @@ -2144,22 +2080,18 @@ "filePath" : "built-ins/Temporal/Instant/prototype/add/minimum-maximum-instant.js", "status" : "FAIL", "comment" : "new failures 2022-08-08" - }, { - "filePath" : "built-ins/Temporal/Instant/prototype/epochMicroseconds/basic.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" }, { "filePath" : "built-ins/Temporal/Instant/prototype/epochMilliseconds/basic.js", "status" : "FAIL", "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/Instant/prototype/epochSeconds/basic.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" }, { "filePath" : "built-ins/Temporal/Instant/prototype/equals/argument-string-date-with-utc-offset.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" + }, { + "filePath" : "built-ins/Temporal/Instant/prototype/equals/argument-string-minus-sign.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "built-ins/Temporal/Instant/prototype/equals/argument-string-multiple-time-zone.js", "status" : "FAIL", @@ -2172,6 +2104,10 @@ "filePath" : "built-ins/Temporal/Instant/prototype/since/argument-string-date-with-utc-offset.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" + }, { + "filePath" : "built-ins/Temporal/Instant/prototype/since/argument-string-minus-sign.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "built-ins/Temporal/Instant/prototype/since/argument-string-multiple-time-zone.js", "status" : "FAIL", @@ -2181,17 +2117,21 @@ "status" : "FAIL", "comment" : "new failures 2023-10-09" }, { - "filePath" : "built-ins/Temporal/Instant/prototype/subtract/minimum-maximum-instant.js", + "filePath" : "built-ins/Temporal/Instant/prototype/since/order-of-operations.js", "status" : "FAIL", - "comment" : "new failures 2022-08-08" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/Instant/prototype/toZonedDateTimeISO/calendar-is-builtin.js", + "filePath" : "built-ins/Temporal/Instant/prototype/subtract/minimum-maximum-instant.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2022-08-08" }, { "filePath" : "built-ins/Temporal/Instant/prototype/until/argument-string-date-with-utc-offset.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" + }, { + "filePath" : "built-ins/Temporal/Instant/prototype/until/argument-string-minus-sign.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "built-ins/Temporal/Instant/prototype/until/argument-string-multiple-time-zone.js", "status" : "FAIL", @@ -2201,89 +2141,45 @@ "status" : "FAIL", "comment" : "new failures 2023-10-09" }, { - "filePath" : "built-ins/Temporal/PlainDate/argument-convert.js", - "status" : "FAIL", - "comment" : "new failures 2023-01-17" - }, { - "filePath" : "built-ins/Temporal/PlainDate/basic.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/PlainDate/from/argument-plaindatetime.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/PlainDate/from/argument-zoneddatetime.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/PlainDate/from/calendar-temporal-object.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/day/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/dayOfWeek/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/dayOfYear/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/daysInMonth/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/daysInWeek/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/daysInYear/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/getCalendar/branding.js", + "filePath" : "built-ins/Temporal/Instant/prototype/until/order-of-operations.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/getCalendar/builtin.js", + "filePath" : "built-ins/Temporal/PlainDate/argument-convert.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2023-01-17" }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/getCalendar/length.js", + "filePath" : "built-ins/Temporal/PlainDate/calendar-iso-string.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/getCalendar/name.js", + "filePath" : "built-ins/Temporal/PlainDate/compare/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/getCalendar/not-a-constructor.js", + "filePath" : "built-ins/Temporal/PlainDate/from/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/getCalendar/prop-desc.js", + "filePath" : "built-ins/Temporal/PlainDate/from/observable-get-overflow-argument-primitive.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/inLeapYear/validate-calendar-value.js", + "filePath" : "built-ins/Temporal/PlainDate/from/observable-get-overflow-argument-string-invalid.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/month/validate-calendar-value.js", + "filePath" : "built-ins/Temporal/PlainDate/from/order-of-operations.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/monthCode/validate-calendar-value.js", + "filePath" : "built-ins/Temporal/PlainDate/prototype/equals/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2023-02-13" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/monthsInYear/validate-calendar-value.js", + "filePath" : "built-ins/Temporal/PlainDate/prototype/since/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-08-09" }, { "filePath" : "built-ins/Temporal/PlainDate/prototype/since/order-of-operations.js", "status" : "FAIL", @@ -2296,6 +2192,10 @@ "filePath" : "built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-calendar-annotation.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" + }, { + "filePath" : "built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-minus-sign.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-time-designator-required-for-disambiguation.js", "status" : "FAIL", @@ -2304,14 +2204,14 @@ "filePath" : "built-ins/Temporal/PlainDate/prototype/toPlainDateTime/argument-string-unknown-annotation.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/toPlainDateTime/custom.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" }, { "filePath" : "built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-calendar-annotation.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" + }, { + "filePath" : "built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-minus-sign.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "built-ins/Temporal/PlainDate/prototype/toZonedDateTime/argument-string-time-designator-required-for-disambiguation.js", "status" : "FAIL", @@ -2321,21 +2221,9 @@ "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/toZonedDateTime/calendar.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/toZonedDateTime/getoffsetnanosecondsfor-out-of-range-forward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/toZonedDateTime/getpossibleinstantsfor-out-of-range-backward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/toZonedDateTime/timezone-getpossibleinstantsfor.js", + "filePath" : "built-ins/Temporal/PlainDate/prototype/until/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-08-09" }, { "filePath" : "built-ins/Temporal/PlainDate/prototype/until/order-of-operations.js", "status" : "FAIL", @@ -2345,41 +2233,33 @@ "status" : "FAIL", "comment" : "new failures 2024-03-15" }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/weekOfYear/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/withCalendar/basic.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/withCalendar/subclassing-ignored.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/year/validate-calendar-value.js", + "filePath" : "built-ins/Temporal/PlainDate/prototype/with/order-of-operations.js", "status" : "FAIL", - "comment" : "new failures 2023-01-17" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainDate/prototype/yearOfWeek/validate-calendar-value.js", + "filePath" : "built-ins/Temporal/PlainDateTime/calendar-iso-string.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainDateTime/constructor-full.js", + "filePath" : "built-ins/Temporal/PlainDateTime/compare/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainDateTime/from/argument-plaindate.js", + "filePath" : "built-ins/Temporal/PlainDateTime/from/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-08-09" }, { "filePath" : "built-ins/Temporal/PlainDateTime/from/argument-string-subsecond.js", "status" : "FAIL", "comment" : "new failures 2022-05-20" }, { - "filePath" : "built-ins/Temporal/PlainDateTime/from/calendar-temporal-object.js", + "filePath" : "built-ins/Temporal/PlainDateTime/from/observable-get-overflow-argument-primitive.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-08-09" + }, { + "filePath" : "built-ins/Temporal/PlainDateTime/from/observable-get-overflow-argument-string-invalid.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "built-ins/Temporal/PlainDateTime/from/order-of-operations.js", "status" : "FAIL", @@ -2389,69 +2269,9 @@ "status" : "FAIL", "comment" : "new failures 2023-10-09" }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/day/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/dayOfWeek/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/dayOfYear/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/daysInMonth/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/daysInWeek/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/daysInYear/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/getCalendar/branding.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/getCalendar/builtin.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/getCalendar/length.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/getCalendar/name.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/getCalendar/not-a-constructor.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/getCalendar/prop-desc.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/inLeapYear/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/month/validate-calendar-value.js", + "filePath" : "built-ins/Temporal/PlainDateTime/prototype/equals/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/monthCode/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2023-02-13" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/monthsInYear/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-08-09" }, { "filePath" : "built-ins/Temporal/PlainDateTime/prototype/round/balance.js", "status" : "FAIL", @@ -2500,30 +2320,34 @@ "filePath" : "built-ins/Temporal/PlainDateTime/prototype/round/roundingmode-halfTrunc.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" + }, { + "filePath" : "built-ins/Temporal/PlainDateTime/prototype/since/argument-string-minus-sign.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" + }, { + "filePath" : "built-ins/Temporal/PlainDateTime/prototype/since/order-of-operations.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "built-ins/Temporal/PlainDateTime/prototype/since/wrapping-at-end-of-month.js", "status" : "FAIL", "comment" : "new failures 2024-03-15" }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/getoffsetnanosecondsfor-out-of-range-forward-offset-shift.js", + "filePath" : "built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/fixed-offset-near-date-time-limits.js", "status" : "FAIL", - "comment" : "new failures 2024-03-15" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/getpossibleinstantsfor-out-of-range-backward-offset-shift.js", + "filePath" : "built-ins/Temporal/PlainDateTime/prototype/until/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2024-03-15" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/toZonedDateTime/plain-custom-timezone.js", + "filePath" : "built-ins/Temporal/PlainDateTime/prototype/until/order-of-operations.js", "status" : "FAIL", - "comment" : "Temporal failures" + "comment" : "new failures 2024-08-09" }, { "filePath" : "built-ins/Temporal/PlainDateTime/prototype/until/wrapping-at-end-of-month.js", "status" : "FAIL", "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/weekOfYear/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" }, { "filePath" : "built-ins/Temporal/PlainDateTime/prototype/with/order-of-operations.js", "status" : "FAIL", @@ -2533,131 +2357,91 @@ "status" : "FAIL", "comment" : "new failures 2023-10-09" }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/withCalendar/basic.js", + "filePath" : "built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-calendar-annotation.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/withCalendar/subclassing-ignored.js", + "filePath" : "built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-noniso.js", + "filePath" : "built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-time-designator-required-for-disambiguation.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2022-02-23" }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-same-id.js", + "filePath" : "built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-unknown-annotation.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-same-object.js", + "filePath" : "built-ins/Temporal/PlainMonthDay/calendar-iso-string.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar.js", + "filePath" : "built-ins/Temporal/PlainMonthDay/from/argument-string-date-with-utc-offset.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-iso-calendar.js", + "filePath" : "built-ins/Temporal/PlainMonthDay/from/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/withPlainDate/calendar-temporal-object.js", + "filePath" : "built-ins/Temporal/PlainMonthDay/from/observable-get-overflow-argument-primitive.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-calendar-annotation.js", + "filePath" : "built-ins/Temporal/PlainMonthDay/from/observable-get-overflow-argument-string-invalid.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-time-designator-required-for-disambiguation.js", + "filePath" : "built-ins/Temporal/PlainMonthDay/from/order-of-operations.js", "status" : "FAIL", - "comment" : "new failures 2022-02-23" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/withPlainTime/argument-string-unknown-annotation.js", + "filePath" : "built-ins/Temporal/PlainMonthDay/prototype/equals/argument-string-date-with-utc-offset.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/year/validate-calendar-value.js", + "filePath" : "built-ins/Temporal/PlainMonthDay/prototype/equals/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2023-01-17" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainDateTime/prototype/yearOfWeek/validate-calendar-value.js", + "filePath" : "built-ins/Temporal/PlainMonthDay/prototype/toPlainDate/default-overflow-behaviour.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-01-15" }, { - "filePath" : "built-ins/Temporal/PlainMonthDay/from/argument-string-date-with-utc-offset.js", + "filePath" : "built-ins/Temporal/PlainMonthDay/prototype/with/order-of-operations.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainMonthDay/from/calendar-temporal-object.js", + "filePath" : "built-ins/Temporal/PlainMonthDay/refisoyear-out-of-range.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2022-08-08" }, { - "filePath" : "built-ins/Temporal/PlainMonthDay/prototype/day/validate-calendar-value.js", + "filePath" : "built-ins/Temporal/PlainTime/compare/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainMonthDay/prototype/equals/argument-string-date-with-utc-offset.js", + "filePath" : "built-ins/Temporal/PlainTime/compare/argument-string-time-designator-required-for-disambiguation.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2022-02-23" }, { - "filePath" : "built-ins/Temporal/PlainMonthDay/prototype/getCalendar/branding.js", + "filePath" : "built-ins/Temporal/PlainTime/compare/argument-string-unknown-annotation.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainMonthDay/prototype/getCalendar/builtin.js", + "filePath" : "built-ins/Temporal/PlainTime/from/argument-string-calendar-annotation.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainMonthDay/prototype/getCalendar/length.js", + "filePath" : "built-ins/Temporal/PlainTime/from/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainMonthDay/prototype/getCalendar/name.js", + "filePath" : "built-ins/Temporal/PlainTime/from/argument-string-time-designator-required-for-disambiguation.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2022-02-23" }, { - "filePath" : "built-ins/Temporal/PlainMonthDay/prototype/getCalendar/not-a-constructor.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/PlainMonthDay/prototype/getCalendar/prop-desc.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/PlainMonthDay/prototype/monthCode/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2023-02-13" - }, { - "filePath" : "built-ins/Temporal/PlainMonthDay/prototype/toPlainDate/calendar-fromfields-called-with-undefined-options.js", - "status" : "FAIL", - "comment" : "new failures 2024-04-12" - }, { - "filePath" : "built-ins/Temporal/PlainMonthDay/prototype/toPlainDate/default-overflow-behaviour.js", - "status" : "FAIL", - "comment" : "new failures 2024-01-15" - }, { - "filePath" : "built-ins/Temporal/PlainMonthDay/refisoyear-out-of-range.js", - "status" : "FAIL", - "comment" : "new failures 2022-08-08" - }, { - "filePath" : "built-ins/Temporal/PlainTime/compare/argument-string-time-designator-required-for-disambiguation.js", - "status" : "FAIL", - "comment" : "new failures 2022-02-23" - }, { - "filePath" : "built-ins/Temporal/PlainTime/compare/argument-string-unknown-annotation.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainTime/from/argument-string-calendar-annotation.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainTime/from/argument-string-time-designator-required-for-disambiguation.js", - "status" : "FAIL", - "comment" : "new failures 2022-02-23" - }, { - "filePath" : "built-ins/Temporal/PlainTime/from/argument-string-unknown-annotation.js", + "filePath" : "built-ins/Temporal/PlainTime/from/argument-string-unknown-annotation.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { @@ -2672,6 +2456,10 @@ "filePath" : "built-ins/Temporal/PlainTime/prototype/equals/argument-string-calendar-annotation.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" + }, { + "filePath" : "built-ins/Temporal/PlainTime/prototype/equals/argument-string-minus-sign.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "built-ins/Temporal/PlainTime/prototype/equals/argument-string-time-designator-required-for-disambiguation.js", "status" : "FAIL", @@ -2680,14 +2468,14 @@ "filePath" : "built-ins/Temporal/PlainTime/prototype/equals/argument-string-unknown-annotation.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/PlainTime/prototype/getISOFields/field-traversal-order.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" }, { "filePath" : "built-ins/Temporal/PlainTime/prototype/since/argument-string-calendar-annotation.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" + }, { + "filePath" : "built-ins/Temporal/PlainTime/prototype/since/argument-string-minus-sign.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "built-ins/Temporal/PlainTime/prototype/since/argument-string-time-designator-required-for-disambiguation.js", "status" : "FAIL", @@ -2696,6 +2484,10 @@ "filePath" : "built-ins/Temporal/PlainTime/prototype/since/argument-string-unknown-annotation.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" + }, { + "filePath" : "built-ins/Temporal/PlainTime/prototype/since/order-of-operations.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "built-ins/Temporal/PlainTime/prototype/subtract/argument-string-duration-too-large.js", "status" : "FAIL", @@ -2705,1260 +2497,440 @@ "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainTime/prototype/toPlainDateTime/calendar-temporal-object.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/PlainTime/prototype/toZonedDateTime/basic.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/PlainTime/prototype/toZonedDateTime/calendar-temporal-object.js", + "filePath" : "built-ins/Temporal/PlainTime/prototype/until/argument-string-calendar-annotation.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainTime/prototype/toZonedDateTime/getoffsetnanosecondsfor-out-of-range-forward-offset-shift.js", + "filePath" : "built-ins/Temporal/PlainTime/prototype/until/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2024-03-15" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainTime/prototype/toZonedDateTime/getpossibleinstantsfor-out-of-range-backward-offset-shift.js", + "filePath" : "built-ins/Temporal/PlainTime/prototype/until/argument-string-time-designator-required-for-disambiguation.js", "status" : "FAIL", - "comment" : "new failures 2024-03-15" + "comment" : "new failures 2022-02-23" }, { - "filePath" : "built-ins/Temporal/PlainTime/prototype/until/argument-string-calendar-annotation.js", + "filePath" : "built-ins/Temporal/PlainTime/prototype/until/argument-string-unknown-annotation.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainTime/prototype/until/argument-string-time-designator-required-for-disambiguation.js", + "filePath" : "built-ins/Temporal/PlainTime/prototype/until/order-of-operations.js", "status" : "FAIL", - "comment" : "new failures 2022-02-23" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainTime/prototype/until/argument-string-unknown-annotation.js", + "filePath" : "built-ins/Temporal/PlainYearMonth/calendar-iso-string.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-08-09" }, { "filePath" : "built-ins/Temporal/PlainYearMonth/compare/argument-string-date-with-utc-offset.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/from/argument-string-date-with-utc-offset.js", + "filePath" : "built-ins/Temporal/PlainYearMonth/compare/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/from/calendar-temporal-object.js", + "filePath" : "built-ins/Temporal/PlainYearMonth/from/argument-string-date-with-utc-offset.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/add/calendar-dateadd-called-with-plaindate-instance.js", + "filePath" : "built-ins/Temporal/PlainYearMonth/from/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/add/calendar-datefromfields-called.js", + "filePath" : "built-ins/Temporal/PlainYearMonth/from/observable-get-overflow-argument-primitive.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/add/custom-daysInMonth-irrelevant.js", + "filePath" : "built-ins/Temporal/PlainYearMonth/from/observable-get-overflow-argument-string-invalid.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/add/end-of-month-out-of-range.js", + "filePath" : "built-ins/Temporal/PlainYearMonth/from/order-of-operations.js", "status" : "FAIL", - "comment" : "new failures 2023-10-23" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/daysInMonth/validate-calendar-value.js", + "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/add/order-of-operations.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/daysInYear/validate-calendar-value.js", + "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/add/overflow-wrong-type.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-08-09" }, { "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-date-with-utc-offset.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/getCalendar/branding.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/getCalendar/builtin.js", + "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/equals/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/getCalendar/length.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/getCalendar/name.js", + "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-date-with-utc-offset.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/getCalendar/not-a-constructor.js", + "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/getCalendar/prop-desc.js", + "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/since/order-of-operations.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/inLeapYear/validate-calendar-value.js", + "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/subtract/order-of-operations.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/month/validate-calendar-value.js", + "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/subtract/overflow-wrong-type.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/monthCode/validate-calendar-value.js", + "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/default-overflow-behaviour.js", "status" : "FAIL", - "comment" : "new failures 2023-02-13" + "comment" : "new failures 2024-01-15" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/monthsInYear/validate-calendar-value.js", + "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-date-with-utc-offset.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/since/argument-string-date-with-utc-offset.js", + "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/since/order-of-operations.js", + "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/until/order-of-operations.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-arguments-extra-options.js", + "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/with/order-of-operations.js", "status" : "FAIL", - "comment" : "Temporal failures" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-arguments.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/calendar-iso-string.js", "status" : "FAIL", - "comment" : "Temporal failures" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-dateadd-called-with-plaindate-instance.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/compare/argument-propertybag-invalid-offset-string.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2023-10-09" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-dateadd.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/compare/argument-string-date-with-utc-offset.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-datefromfields-called.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/compare/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/subtract/calendar-fromfields-called-with-null-prototype-fields.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/compare/zoneddatetime-string.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "Temporal failures" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/subtract/custom-daysInMonth-irrelevant.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/from/argument-propertybag-invalid-offset-string.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2023-10-09" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/subtract/end-of-month-out-of-range.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/from/argument-string-date-with-utc-offset.js", "status" : "FAIL", - "comment" : "new failures 2023-10-23" + "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/subtract/options-undefined.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/from/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/subtract/order-of-operations.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/from/argument-string-time-zone-annotation.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/calendar-fromfields-called-with-undefined-options.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/from/observable-get-overflow-argument-primitive.js", "status" : "FAIL", - "comment" : "new failures 2024-04-12" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/toPlainDate/default-overflow-behaviour.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/from/observable-get-overflow-argument-string-invalid.js", "status" : "FAIL", - "comment" : "new failures 2024-01-15" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/until/argument-string-date-with-utc-offset.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/from/offset-overrides-critical-flag.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/until/order-of-operations.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/from/order-of-operations.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/PlainYearMonth/prototype/year/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2023-01-17" - }, { - "filePath" : "built-ins/Temporal/TimeZone/argument-wrong-type.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/from/overflow-wrong-type.js", "status" : "FAIL", "comment" : "new failures 2023-10-09" }, { - "filePath" : "built-ins/Temporal/TimeZone/basic.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/from/zoneddatetime-string.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "Temporal failures" }, { - "filePath" : "built-ins/Temporal/TimeZone/from/argument-object.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/epochMilliseconds/basic.js", "status" : "FAIL", "comment" : "new failures 2023-05-16" }, { - "filePath" : "built-ins/Temporal/TimeZone/missing-arguments.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/equals/argument-propertybag-invalid-offset-string.js", "status" : "FAIL", "comment" : "new failures 2023-10-09" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/equals/argument-object.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/equals/argument-propertybag-timezone-string-datetime.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/equals/argument-primitive.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/equals/argument-string-date-with-utc-offset.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/equals/argument-valid.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/equals/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/equals/branding.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/equals/argument-string-time-zone-annotation.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/equals/builtin.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/equals/zoneddatetime-string.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "Temporal failures" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/equals/length.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getTimeZoneTransition/branding.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/equals/name.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getTimeZoneTransition/builtin.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/equals/not-a-constructor.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getTimeZoneTransition/direction-undefined.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/equals/prop-desc.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getTimeZoneTransition/direction-wrong-type.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/equals/timezone-case-insensitive.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getTimeZoneTransition/length.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/equals/timezone-string-datetime.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getTimeZoneTransition/name.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/equals/timezone-string-multiple-offsets.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getTimeZoneTransition/not-a-constructor.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/equals/timezone-wrong-type.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getTimeZoneTransition/offset-timezone-no-transitions.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/getInstantFor/getoffsetnanosecondsfor-out-of-range-forward-offset-shift.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getTimeZoneTransition/prop-desc.js", "status" : "FAIL", - "comment" : "new failures 2024-03-15" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/getInstantFor/getpossibleinstantsfor-out-of-range-backward-offset-shift.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getTimeZoneTransition/utc-no-transitions.js", "status" : "FAIL", - "comment" : "new failures 2024-03-15" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-date-with-utc-offset.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getTimeZoneTransition/wrong-string.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-string-multiple-time-zone.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/round/roundingmode-halfCeil.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/getNextTransition/argument-wrong-type.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-date-with-utc-offset.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/round/roundingmode-halfEven.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-string-multiple-time-zone.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/round/roundingmode-halfExpand.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/getOffsetNanosecondsFor/argument-wrong-type.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-not-absolute-getOffsetNanosecondsFor-override.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-date-with-utc-offset.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/round/roundingmode-halfFloor.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-string-multiple-time-zone.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/round/roundingmode-halfTrunc.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/getOffsetStringFor/argument-wrong-type.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-not-absolute-getOffsetNanosecondsFor-override.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/argument-propertybag-invalid-offset-string.js", "status" : "FAIL", "comment" : "new failures 2023-10-09" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-date-with-utc-offset.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/argument-string-date-with-utc-offset.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-string-multiple-time-zone.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/getPlainDateTimeFor/argument-wrong-type.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/order-of-operations.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/getPossibleInstantsFor/fixed-offset-near-date-time-limits.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/wrapping-at-end-of-month.js", "status" : "FAIL", - "comment" : "new failures 2022-08-08" + "comment" : "new failures 2024-03-15" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-date-with-utc-offset.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/zoneddatetime-string.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "Temporal failures" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-string-multiple-time-zone.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/toPlainDateTime/pre-epoch.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/getPreviousTransition/argument-wrong-type.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/argument-propertybag-invalid-offset-string.js", "status" : "FAIL", "comment" : "new failures 2023-10-09" }, { - "filePath" : "built-ins/Temporal/TimeZone/prototype/toJSON/returns-identifier-slot.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/argument-string-date-with-utc-offset.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/compare/argument-propertybag-invalid-offset-string.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/compare/argument-propertybag-out-of-range-backward-offset-shift.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/order-of-operations.js", "status" : "FAIL", - "comment" : "new failures 2024-03-15" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/compare/argument-propertybag-out-of-range-forward-offset-shift.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/wrapping-at-end-of-month.js", "status" : "FAIL", "comment" : "new failures 2024-03-15" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/compare/argument-string-date-with-utc-offset.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/compare/zoneddatetime-string.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/zoneddatetime-string.js", "status" : "FAIL", "comment" : "Temporal failures" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/from/argument-propertybag-ambiguous-wall-clock-time.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/from/argument-propertybag-invalid-offset-string.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/with/offset-property-invalid-string.js", "status" : "FAIL", "comment" : "new failures 2023-10-09" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/from/argument-propertybag-out-of-range-backward-offset-shift.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/with/order-of-operations.js", "status" : "FAIL", - "comment" : "new failures 2024-03-15" + "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/from/argument-propertybag-out-of-range-forward-offset-shift.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/with/overflow-wrong-type.js", "status" : "FAIL", - "comment" : "new failures 2024-03-15" + "comment" : "new failures 2023-10-09" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/from/argument-string-date-with-utc-offset.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/withPlainTime/argument-string-calendar-annotation.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/from/argument-string-time-zone-annotation.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/withPlainTime/argument-string-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/from/calendar-temporal-object.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/withPlainTime/argument-string-time-designator-required-for-disambiguation.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2022-02-23" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/from/offset-overrides-critical-flag.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/withPlainTime/argument-string-unknown-annotation.js", "status" : "FAIL", "comment" : "new failures 2022-11-30" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/from/order-of-operations.js", + "filePath" : "built-ins/Temporal/ZonedDateTime/timezone-iso-string.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/from/overflow-wrong-type.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "filePath" : "built-ins/TypedArray/prototype/set/typedarray-arg-set-values-same-buffer-other-type.js", + "status" : "PASS", + "statusOverrides" : { + "BIG_ENDIAN" : "FAIL" + }, + "comment" : "Incorrect test (assumes little endian platform), see https://github.com/tc39/test262/issues/757" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/from/zoneddatetime-string.js", + "filePath" : "intl402/Collator/prototype/resolvedOptions/ignorePunctuation-default.js", "status" : "FAIL", - "comment" : "Temporal failures" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/day/validate-calendar-value.js", + "filePath" : "intl402/DateTimeFormat/offset-timezone-no-unicode-minus-sign.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/dayOfWeek/validate-calendar-value.js", + "filePath" : "intl402/DateTimeFormat/prototype/format/temporal-objects-resolved-time-zone.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "Temporal failures" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/dayOfYear/validate-calendar-value.js", + "filePath" : "intl402/DateTimeFormat/prototype/formatRange/temporal-objects-resolved-time-zone.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "Temporal failures" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/daysInMonth/validate-calendar-value.js", + "filePath" : "intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-objects-resolved-time-zone.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "Temporal failures" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/daysInWeek/validate-calendar-value.js", + "filePath" : "intl402/DateTimeFormat/prototype/formatToParts/temporal-objects-resolved-time-zone.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "Temporal failures" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/daysInYear/validate-calendar-value.js", + "filePath" : "intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-default.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-03-15" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/epochMicroseconds/basic.js", + "filePath" : "intl402/DateTimeFormat/timezone-case-insensitive.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2023-10-09" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/epochMilliseconds/basic.js", + "filePath" : "intl402/DateTimeFormat/timezone-legacy-non-iana.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-03-15" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/epochSeconds/basic.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/equals/argument-propertybag-invalid-offset-string.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/equals/argument-propertybag-out-of-range-backward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/equals/argument-propertybag-out-of-range-forward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/equals/argument-propertybag-timezone-normalize-offset-strings.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/equals/argument-propertybag-timezone-string-datetime.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/equals/argument-string-date-with-utc-offset.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/equals/argument-string-time-zone-annotation.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/equals/zoneddatetime-string.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getCalendar/branding.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getCalendar/builtin.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getCalendar/length.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getCalendar/name.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getCalendar/not-a-constructor.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getCalendar/prop-desc.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getISOFields/order-of-operations.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getTimeZone/branding.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getTimeZone/builtin.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getTimeZone/length.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getTimeZone/name.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getTimeZone/not-a-constructor.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/getTimeZone/prop-desc.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/hoursInDay/getoffsetnanosecondsfor-out-of-range-forward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/hoursInDay/getpossibleinstantsfor-out-of-range-backward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/hoursInDay/precision-exact-mathematical-values-2.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/hoursInDay/precision-exact-mathematical-values.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/inLeapYear/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/month/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/monthCode/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2023-02-13" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/monthsInYear/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/round/getpossibleinstantsfor-called-with-iso8601-calendar.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-23" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/round/getpossibleinstantsfor-out-of-range-backward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/round/order-of-operations.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/round/rounding-is-noop.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/round/roundingmode-halfCeil.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/round/roundingmode-halfEven.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/round/roundingmode-halfExpand.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/round/roundingmode-halfFloor.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/round/roundingmode-halfTrunc.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/round/smallest-unit-day-daylength-too-large.js", - "status" : "FAIL", - "comment" : "new failures 2022-08-08" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/round/smallest-unit-day-daylength-zero-or-negative.js", - "status" : "FAIL", - "comment" : "new failures 2022-08-08" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/round/smallest-unit-day-rounding-modes.js", - "status" : "FAIL", - "comment" : "new failures 2022-08-08" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/round/timezone-getpossibleinstantsfor-iterable.js", - "status" : "FAIL", - "comment" : "new failures 2024-04-12" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/argument-propertybag-invalid-offset-string.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/argument-propertybag-out-of-range-backward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/argument-propertybag-out-of-range-forward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/argument-string-date-with-utc-offset.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/wrapping-at-end-of-month.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/since/zoneddatetime-string.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/startOfDay/getoffsetnanosecondsfor-out-of-range-forward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/startOfDay/getpossibleinstantsfor-out-of-range-backward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/argument-propertybag-invalid-offset-string.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/argument-propertybag-out-of-range-backward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/argument-propertybag-out-of-range-forward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/argument-string-date-with-utc-offset.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/wrapping-at-end-of-month.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/until/zoneddatetime-string.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/weekOfYear/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/with/balance-negative-time-units.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/with/getoffsetnanosecondsfor-out-of-range-forward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/with/getpossibleinstantsfor-called-with-iso8601-calendar.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-23" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/with/getpossibleinstantsfor-out-of-range-backward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/with/offset-property-invalid-string.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/with/order-of-operations.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/with/overflow-wrong-type.js", + "filePath" : "intl402/DateTimeFormat/timezone-not-canonicalized.js", "status" : "FAIL", "comment" : "new failures 2023-10-09" }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/withCalendar/subclassing-ignored.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/withPlainDate/calendar-temporal-object.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/withPlainDate/getoffsetnanosecondsfor-out-of-range-forward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/withPlainDate/getpossibleinstantsfor-out-of-range-backward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/withPlainTime/argument-string-calendar-annotation.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/withPlainTime/argument-string-time-designator-required-for-disambiguation.js", - "status" : "FAIL", - "comment" : "new failures 2022-02-23" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/withPlainTime/argument-string-unknown-annotation.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/withPlainTime/getoffsetnanosecondsfor-out-of-range-forward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/withPlainTime/getpossibleinstantsfor-out-of-range-backward-offset-shift.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/year/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2023-01-17" - }, { - "filePath" : "built-ins/Temporal/ZonedDateTime/prototype/yearOfWeek/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "built-ins/TypedArray/prototype/set/typedarray-arg-set-values-same-buffer-other-type.js", + "filePath" : "intl402/Intl/getCanonicalLocales/canonicalized-tags.js", "status" : "PASS", "statusOverrides" : { - "BIG_ENDIAN" : "FAIL" + "COMPILE_IMMEDIATELY" : "SKIP" }, - "comment" : "Incorrect test (assumes little endian platform), see https://github.com/tc39/test262/issues/757" - }, { - "filePath" : "intl402/DateTimeFormat/prototype/format/temporal-objects-resolved-time-zone.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/DateTimeFormat/prototype/formatRange/temporal-objects-resolved-time-zone.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/DateTimeFormat/prototype/formatRangeToParts/temporal-objects-resolved-time-zone.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/DateTimeFormat/prototype/formatToParts/temporal-objects-resolved-time-zone.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/DateTimeFormat/prototype/resolvedOptions/hourCycle-default.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "intl402/DateTimeFormat/timezone-case-insensitive.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "intl402/DateTimeFormat/timezone-legacy-non-iana.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "intl402/DateTimeFormat/timezone-not-canonicalized.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "intl402/Intl/getCanonicalLocales/canonicalized-tags.js", - "status" : "PASS", - "statusOverrides" : { - "COMPILE_IMMEDIATELY" : "SKIP" - }, - "comment" : "Long-running in compile mode" + "comment" : "Long-running in compile mode" }, { "filePath" : "intl402/Intl/getCanonicalLocales/transformed-ext-valid.js", "status" : "PASS", "statusOverrides" : { "COMPILE_IMMEDIATELY" : "SKIP" - }, - "comment" : "Long-running in compile mode" - }, { - "filePath" : "intl402/language-tags-canonicalized.js", - "status" : "PASS", - "statusOverrides" : { - "COMPILE_IMMEDIATELY" : "SKIP" - }, - "comment" : "Long-running in compile mode" - }, { - "filePath" : "intl402/NumberFormat/prototype/format/format-significant-digits.js", - "status" : "PASS", - "statusOverrides" : { - "COMPILE_IMMEDIATELY" : "SKIP" - }, - "comment" : "Long-running in compile mode" - }, { - "filePath" : "intl402/Temporal/Calendar/calendar-case-insensitive.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/dateAdd/date-infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/dateFromFields/infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/dateFromFields/one-of-era-erayear-undefined.js", - "status" : "FAIL", - "comment" : "new failures 2023-03-10" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/dateFromFields/order-of-operations.js", - "status" : "FAIL", - "comment" : "new failures 2022-07-13" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/dateUntil/argument-infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/dateUntil/until-across-lunisolar-leap-months.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/dateUntil/zero-length-duration-result.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/day/infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/dayOfWeek/infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/dayOfYear/infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/daysInMonth/infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/daysInWeek/infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/daysInYear/infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-builtin-calendar-no-array-iteration.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-calendar-datefromfields-called-with-null-prototype-fields.js", - "status" : "FAIL", - "comment" : "new failures 2022-07-13" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-constructor-in-calendar-fields.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-duplicate-calendar-fields.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-leap-second.js", - "status" : "FAIL", - "comment" : "new failures 2022-05-20" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-propertybag-calendar-case-insensitive.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-propertybag-calendar-iso-string.js", - "status" : "FAIL", - "comment" : "new failures 2024-04-12" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-propertybag-calendar-leap-second.js", - "status" : "FAIL", - "comment" : "new failures 2022-05-20" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-propertybag-calendar-string.js", - "status" : "FAIL", - "comment" : "new failures 2022-08-08" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-propertybag-calendar-wrong-type.js", - "status" : "FAIL", - "comment" : "new failures 2022-05-20" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-propertybag-calendar-year-zero.js", - "status" : "FAIL", - "comment" : "new failures 2022-05-20" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-proto-in-calendar-fields.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-string-calendar-annotation-invalid-key.js", - "status" : "FAIL", - "comment" : "new failures 2024-04-12" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-string-calendar-annotation.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-string-critical-unknown-annotation.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-string-date-with-utc-offset.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-string-invalid.js", - "status" : "FAIL", - "comment" : "new Temporal failures 2022-04-11" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-string-multiple-calendar.js", - "status" : "FAIL", - "comment" : "new failures 2013-06-28" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-string-multiple-time-zone.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-string-time-separators.js", - "status" : "FAIL", - "comment" : "new failures 2022-07-13" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-string-time-zone-annotation.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-string-unknown-annotation.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-string-with-utc-designator.js", - "status" : "FAIL", - "comment" : "new failures 2022-01-25" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-wrong-type.js", - "status" : "FAIL", - "comment" : "new failures 2022-05-20" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-zoneddatetime-convert.js", - "status" : "FAIL", - "comment" : "new failures 2022-05-20" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-zoneddatetime-slots.js", - "status" : "FAIL", - "comment" : "new failures 2022-07-13" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/branding.js", - "status" : "FAIL", - "comment" : "Temporal tests still failing" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/builtin.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/calendar-datefromfields-called-with-options-undefined.js", - "status" : "FAIL", - "comment" : "new Temporal failures 2022-04-11" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/length.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/name.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/not-a-constructor.js", - "status" : "FAIL", - "comment" : "new failures 2023-01-17" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/prop-desc.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/era/year-zero.js", - "status" : "FAIL", - "comment" : "new failures 2022-02-23" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-builtin-calendar-no-array-iteration.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-calendar-datefromfields-called-with-null-prototype-fields.js", - "status" : "FAIL", - "comment" : "new failures 2022-07-13" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-constructor-in-calendar-fields.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-duplicate-calendar-fields.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-leap-second.js", - "status" : "FAIL", - "comment" : "new failures 2022-05-20" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-propertybag-calendar-case-insensitive.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-propertybag-calendar-iso-string.js", - "status" : "FAIL", - "comment" : "new failures 2024-04-12" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-propertybag-calendar-leap-second.js", - "status" : "FAIL", - "comment" : "new failures 2022-05-20" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-propertybag-calendar-string.js", - "status" : "FAIL", - "comment" : "new failures 2022-08-08" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-propertybag-calendar-wrong-type.js", - "status" : "FAIL", - "comment" : "new failures 2022-05-20" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-propertybag-calendar-year-zero.js", - "status" : "FAIL", - "comment" : "new failures 2022-05-20" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-proto-in-calendar-fields.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-string-calendar-annotation-invalid-key.js", - "status" : "FAIL", - "comment" : "new failures 2024-04-12" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-string-calendar-annotation.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-string-critical-unknown-annotation.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-string-date-with-utc-offset.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-string-invalid.js", - "status" : "FAIL", - "comment" : "new Temporal failures 2022-04-11" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-string-multiple-calendar.js", - "status" : "FAIL", - "comment" : "new failures 2013-06-28" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-string-multiple-time-zone.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-string-time-separators.js", - "status" : "FAIL", - "comment" : "new failures 2022-07-13" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-string-time-zone-annotation.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-string-unknown-annotation.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-string-with-utc-designator.js", - "status" : "FAIL", - "comment" : "new failures 2022-01-25" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-wrong-type.js", - "status" : "FAIL", - "comment" : "new failures 2022-05-20" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-zoneddatetime-convert.js", - "status" : "FAIL", - "comment" : "new failures 2022-05-20" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-zoneddatetime-slots.js", - "status" : "FAIL", - "comment" : "new failures 2022-07-13" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-non-integer.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/argument-zoneddatetime-timezone-getoffsetnanosecondsfor-out-of-range.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/branding.js", - "status" : "FAIL", - "comment" : "Temporal tests still failing" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/builtin.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/calendar-datefromfields-called-with-options-undefined.js", - "status" : "FAIL", - "comment" : "new Temporal failures 2022-04-11" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/length.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/name.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/not-a-constructor.js", - "status" : "FAIL", - "comment" : "new failures 2023-01-17" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/prop-desc.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/eraYear/year-zero.js", - "status" : "FAIL", - "comment" : "new failures 2022-02-23" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/inLeapYear/infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/mergeFields/gregorian-mutually-exclusive-fields.js", - "status" : "FAIL", - "comment" : "new failures 2023-03-10" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/mergeFields/japanese-mutually-exclusive-fields.js", - "status" : "FAIL", - "comment" : "new failures 2023-03-10" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/month/infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/monthCode/infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/monthDayFromFields/fields-underspecified.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-30" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/monthDayFromFields/infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/monthDayFromFields/order-of-operations.js", - "status" : "FAIL", - "comment" : "new failures 2022-07-13" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/monthDayFromFields/reference-year-1972.js", - "status" : "FAIL", - "comment" : "new failures 2023-03-10" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/monthsInYear/infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/weekOfYear/gregory-iso-weekofyear.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/weekOfYear/infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/weekOfYear/non-iso-week-of-year.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/year/infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/yearMonthFromFields/infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/yearMonthFromFields/one-of-era-erayear-undefined.js", - "status" : "FAIL", - "comment" : "new failures 2023-03-10" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/yearMonthFromFields/order-of-operations.js", - "status" : "FAIL", - "comment" : "new failures 2022-07-13" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/yearMonthFromFields/reference-day-chinese.js", - "status" : "FAIL", - "comment" : "new failures 2024-06-07" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/yearMonthFromFields/reference-day-gregory.js", - "status" : "FAIL", - "comment" : "new failures 2024-06-07" - }, { - "filePath" : "intl402/Temporal/Calendar/prototype/yearMonthFromFields/reference-day-hebrew.js", - "status" : "FAIL", - "comment" : "new failures 2024-06-07" + }, + "comment" : "Long-running in compile mode" }, { - "filePath" : "intl402/Temporal/Calendar/prototype/yearOfWeek/gregory-iso-weekofyear.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" + "filePath" : "intl402/language-tags-canonicalized.js", + "status" : "PASS", + "statusOverrides" : { + "COMPILE_IMMEDIATELY" : "SKIP" + }, + "comment" : "Long-running in compile mode" }, { - "filePath" : "intl402/Temporal/Calendar/prototype/yearOfWeek/infinity-throws-rangeerror.js", + "filePath" : "intl402/Locale/constructor-options-firstDayOfWeek-valid.js", "status" : "FAIL", - "comment" : "new failures 2022-11-30" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/Calendar/prototype/yearOfWeek/non-iso-week-of-year.js", + "filePath" : "intl402/Locale/prototype/firstDayOfWeek/valid-id.js", "status" : "FAIL", - "comment" : "new failures 2024-03-15" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/Duration/prototype/add/relativeto-infinity-throws-rangeerror.js", + "filePath" : "intl402/Locale/prototype/firstDayOfWeek/valid-options.js", "status" : "FAIL", - "comment" : "Temporal failures" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/Duration/prototype/add/relativeto-string-datetime.js", - "status" : "FAIL", - "comment" : "new failures 2022-01-25" + "filePath" : "intl402/NumberFormat/prototype/format/format-significant-digits.js", + "status" : "PASS", + "statusOverrides" : { + "COMPILE_IMMEDIATELY" : "SKIP" + }, + "comment" : "Long-running in compile mode" }, { - "filePath" : "intl402/Temporal/Duration/prototype/add/relativeto-sub-minute-offset.js", + "filePath" : "intl402/NumberFormat/prototype/format/useGrouping-extended-en-IN.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/Duration/prototype/round/relativeto-infinity-throws-rangeerror.js", "status" : "FAIL", @@ -3971,18 +2943,6 @@ "filePath" : "intl402/Temporal/Duration/prototype/round/relativeto-sub-minute-offset.js", "status" : "FAIL", "comment" : "new failures 2023-10-09" - }, { - "filePath" : "intl402/Temporal/Duration/prototype/subtract/relativeto-infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/Duration/prototype/subtract/relativeto-string-datetime.js", - "status" : "FAIL", - "comment" : "new failures 2022-01-25" - }, { - "filePath" : "intl402/Temporal/Duration/prototype/subtract/relativeto-sub-minute-offset.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" }, { "filePath" : "intl402/Temporal/Duration/prototype/total/relativeto-infinity-throws-rangeerror.js", "status" : "FAIL", @@ -4011,14 +2971,34 @@ "filePath" : "intl402/Temporal/Instant/prototype/toLocaleString/options-undefined.js", "status" : "FAIL", "comment" : "Temporal failures" + }, { + "filePath" : "intl402/Temporal/PlainDate/canonicalize-calendar.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/PlainDate/compare/infinity-throws-rangeerror.js", "status" : "FAIL", "comment" : "Temporal failures" + }, { + "filePath" : "intl402/Temporal/PlainDate/from/canonicalize-calendar.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/PlainDate/from/infinity-throws-rangeerror.js", "status" : "FAIL", "comment" : "Temporal failures" + }, { + "filePath" : "intl402/Temporal/PlainDate/from/one-of-era-erayear-undefined.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" + }, { + "filePath" : "intl402/Temporal/PlainDate/prototype/equals/argument-object-valid.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" + }, { + "filePath" : "intl402/Temporal/PlainDate/prototype/equals/canonicalize-calendar.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/PlainDate/prototype/equals/infinity-throws-rangeerror.js", "status" : "FAIL", @@ -4031,10 +3011,6 @@ "filePath" : "intl402/Temporal/PlainDate/prototype/era/prop-desc.js", "status" : "FAIL", "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/PlainDate/prototype/era/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2023-02-13" }, { "filePath" : "intl402/Temporal/PlainDate/prototype/eraYear/branding.js", "status" : "FAIL", @@ -4044,9 +3020,9 @@ "status" : "FAIL", "comment" : "Temporal failures" }, { - "filePath" : "intl402/Temporal/PlainDate/prototype/eraYear/validate-calendar-value.js", + "filePath" : "intl402/Temporal/PlainDate/prototype/since/canonicalize-calendar.js", "status" : "FAIL", - "comment" : "new failures 2023-02-13" + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/PlainDate/prototype/since/infinity-throws-rangeerror.js", "status" : "FAIL", @@ -4075,10 +3051,18 @@ "filePath" : "intl402/Temporal/PlainDate/prototype/toLocaleString/resolved-time-zone.js", "status" : "FAIL", "comment" : "Temporal failures" + }, { + "filePath" : "intl402/Temporal/PlainDate/prototype/until/canonicalize-calendar.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/PlainDate/prototype/until/infinity-throws-rangeerror.js", "status" : "FAIL", "comment" : "Temporal failures" + }, { + "filePath" : "intl402/Temporal/PlainDate/prototype/until/until-across-lunisolar-leap-months.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/PlainDate/prototype/weekOfYear/gregory-iso-weekofyear.js", "status" : "FAIL", @@ -4091,6 +3075,18 @@ "filePath" : "intl402/Temporal/PlainDate/prototype/with/cross-era-boundary.js", "status" : "FAIL", "comment" : "new failures 2023-03-10" + }, { + "filePath" : "intl402/Temporal/PlainDate/prototype/with/gregorian-mutually-exclusive-fields.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" + }, { + "filePath" : "intl402/Temporal/PlainDate/prototype/with/japanese-mutually-exclusive-fields.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" + }, { + "filePath" : "intl402/Temporal/PlainDate/prototype/withCalendar/canonicalize-calendar.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/PlainDate/prototype/yearOfWeek/gregory-iso-weekofyear.js", "status" : "FAIL", @@ -4099,14 +3095,26 @@ "filePath" : "intl402/Temporal/PlainDate/prototype/yearOfWeek/non-iso-week-of-year.js", "status" : "FAIL", "comment" : "new failures 2024-03-15" + }, { + "filePath" : "intl402/Temporal/PlainDateTime/canonicalize-calendar.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/PlainDateTime/compare/infinity-throws-rangeerror.js", "status" : "FAIL", "comment" : "Temporal failures" + }, { + "filePath" : "intl402/Temporal/PlainDateTime/from/canonicalize-calendar.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/PlainDateTime/from/infinity-throws-rangeerror.js", "status" : "FAIL", "comment" : "Temporal failures" + }, { + "filePath" : "intl402/Temporal/PlainDateTime/prototype/equals/canonicalize-calendar.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/PlainDateTime/prototype/equals/infinity-throws-rangeerror.js", "status" : "FAIL", @@ -4119,10 +3127,6 @@ "filePath" : "intl402/Temporal/PlainDateTime/prototype/era/prop-desc.js", "status" : "FAIL", "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/PlainDateTime/prototype/era/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2023-02-13" }, { "filePath" : "intl402/Temporal/PlainDateTime/prototype/eraYear/branding.js", "status" : "FAIL", @@ -4132,9 +3136,9 @@ "status" : "FAIL", "comment" : "Temporal failures" }, { - "filePath" : "intl402/Temporal/PlainDateTime/prototype/eraYear/validate-calendar-value.js", + "filePath" : "intl402/Temporal/PlainDateTime/prototype/since/canonicalize-calendar.js", "status" : "FAIL", - "comment" : "new failures 2023-02-13" + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/PlainDateTime/prototype/since/infinity-throws-rangeerror.js", "status" : "FAIL", @@ -4164,45 +3168,37 @@ "status" : "FAIL", "comment" : "Temporal failures" }, { - "filePath" : "intl402/Temporal/PlainDateTime/prototype/until/infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/PlainDateTime/prototype/weekOfYear/gregory-iso-weekofyear.js", - "status" : "FAIL", - "comment" : "new failures 2024-03-15" - }, { - "filePath" : "intl402/Temporal/PlainDateTime/prototype/weekOfYear/non-iso-week-of-year.js", + "filePath" : "intl402/Temporal/PlainDateTime/prototype/toZonedDateTime/dst-disambiguation.js", "status" : "FAIL", - "comment" : "new failures 2024-03-15" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-noniso.js", + "filePath" : "intl402/Temporal/PlainDateTime/prototype/toZonedDateTime/multiple-instants.js", "status" : "FAIL", - "comment" : "new failures 2022-05-20" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-same-id.js", + "filePath" : "intl402/Temporal/PlainDateTime/prototype/toZonedDateTime/order-of-operations.js", "status" : "FAIL", - "comment" : "new failures 2022-05-20" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar-same-object.js", + "filePath" : "intl402/Temporal/PlainDateTime/prototype/until/canonicalize-calendar.js", "status" : "FAIL", - "comment" : "new failures 2022-05-20" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/PlainDateTime/prototype/withPlainDate/argument-plaindate-calendar.js", + "filePath" : "intl402/Temporal/PlainDateTime/prototype/until/infinity-throws-rangeerror.js", "status" : "FAIL", - "comment" : "new failures 2022-05-20" + "comment" : "Temporal failures" }, { - "filePath" : "intl402/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-calendar.js", + "filePath" : "intl402/Temporal/PlainDateTime/prototype/weekOfYear/gregory-iso-weekofyear.js", "status" : "FAIL", - "comment" : "new failures 2022-05-20" + "comment" : "new failures 2024-03-15" }, { - "filePath" : "intl402/Temporal/PlainDateTime/prototype/withPlainDate/argument-string-iso-calendar.js", + "filePath" : "intl402/Temporal/PlainDateTime/prototype/weekOfYear/non-iso-week-of-year.js", "status" : "FAIL", - "comment" : "new failures 2022-05-20" + "comment" : "new failures 2024-03-15" }, { - "filePath" : "intl402/Temporal/PlainDateTime/prototype/withPlainDate/infinity-throws-rangeerror.js", + "filePath" : "intl402/Temporal/PlainDateTime/prototype/withCalendar/canonicalize-calendar.js", "status" : "FAIL", - "comment" : "Temporal failures" + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/PlainDateTime/prototype/yearOfWeek/gregory-iso-weekofyear.js", "status" : "FAIL", @@ -4211,6 +3207,14 @@ "filePath" : "intl402/Temporal/PlainDateTime/prototype/yearOfWeek/non-iso-week-of-year.js", "status" : "FAIL", "comment" : "new failures 2024-03-15" + }, { + "filePath" : "intl402/Temporal/PlainMonthDay/canonicalize-calendar.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" + }, { + "filePath" : "intl402/Temporal/PlainMonthDay/from/canonicalize-calendar.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/PlainMonthDay/from/fields-missing-properties.js", "status" : "FAIL", @@ -4219,10 +3223,22 @@ "filePath" : "intl402/Temporal/PlainMonthDay/from/fields-object.js", "status" : "FAIL", "comment" : "new failures 2023-11-30" + }, { + "filePath" : "intl402/Temporal/PlainMonthDay/from/fields-underspecified.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/PlainMonthDay/from/reference-date-noniso-calendar.js", "status" : "FAIL", "comment" : "new failures 2023-05-16" + }, { + "filePath" : "intl402/Temporal/PlainMonthDay/from/reference-year-1972.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" + }, { + "filePath" : "intl402/Temporal/PlainMonthDay/prototype/equals/canonicalize-calendar.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/PlainMonthDay/prototype/equals/infinity-throws-rangeerror.js", "status" : "FAIL", @@ -4272,13 +3288,9 @@ "status" : "FAIL", "comment" : "Temporal failures" }, { - "filePath" : "intl402/Temporal/PlainTime/prototype/toPlainDateTime/infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/PlainTime/prototype/toZonedDateTime/plaindate-infinity-throws-rangeerror.js", + "filePath" : "intl402/Temporal/PlainYearMonth/canonicalize-calendar.js", "status" : "FAIL", - "comment" : "Temporal failures" + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/PlainYearMonth/compare/infinity-throws-rangeerror.js", "status" : "FAIL", @@ -4287,10 +3299,38 @@ "filePath" : "intl402/Temporal/PlainYearMonth/from/argument-object.js", "status" : "FAIL", "comment" : "new failures 2022-02-23" + }, { + "filePath" : "intl402/Temporal/PlainYearMonth/from/canonicalize-calendar.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/PlainYearMonth/from/infinity-throws-rangeerror.js", "status" : "FAIL", "comment" : "Temporal failures" + }, { + "filePath" : "intl402/Temporal/PlainYearMonth/from/one-of-era-erayear-undefined.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" + }, { + "filePath" : "intl402/Temporal/PlainYearMonth/from/reference-day-chinese.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" + }, { + "filePath" : "intl402/Temporal/PlainYearMonth/from/reference-day-gregory.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" + }, { + "filePath" : "intl402/Temporal/PlainYearMonth/from/reference-day-hebrew.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" + }, { + "filePath" : "intl402/Temporal/PlainYearMonth/prototype/add/options-undefined.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" + }, { + "filePath" : "intl402/Temporal/PlainYearMonth/prototype/equals/canonicalize-calendar.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/PlainYearMonth/prototype/equals/infinity-throws-rangeerror.js", "status" : "FAIL", @@ -4303,10 +3343,6 @@ "filePath" : "intl402/Temporal/PlainYearMonth/prototype/era/prop-desc.js", "status" : "FAIL", "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/PlainYearMonth/prototype/era/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2023-02-13" }, { "filePath" : "intl402/Temporal/PlainYearMonth/prototype/eraYear/branding.js", "status" : "FAIL", @@ -4316,13 +3352,17 @@ "status" : "FAIL", "comment" : "Temporal failures" }, { - "filePath" : "intl402/Temporal/PlainYearMonth/prototype/eraYear/validate-calendar-value.js", + "filePath" : "intl402/Temporal/PlainYearMonth/prototype/since/canonicalize-calendar.js", "status" : "FAIL", - "comment" : "new failures 2023-02-13" + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/PlainYearMonth/prototype/since/infinity-throws-rangeerror.js", "status" : "FAIL", "comment" : "Temporal failures" + }, { + "filePath" : "intl402/Temporal/PlainYearMonth/prototype/subtract/options-undefined.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/PlainYearMonth/prototype/toLocaleString/calendar-mismatch.js", "status" : "FAIL", @@ -4344,137 +3384,105 @@ "status" : "FAIL", "comment" : "Temporal failures" }, { - "filePath" : "intl402/Temporal/PlainYearMonth/prototype/until/infinity-throws-rangeerror.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/TimeZone/basic.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "intl402/Temporal/TimeZone/etc-timezone.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "intl402/Temporal/TimeZone/from/argument-object.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" - }, { - "filePath" : "intl402/Temporal/TimeZone/from/argument-valid.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" - }, { - "filePath" : "intl402/Temporal/TimeZone/from/etc-timezone.js", - "status" : "FAIL", - "comment" : "new failures 2022-08-08" - }, { - "filePath" : "intl402/Temporal/TimeZone/from/iana-legacy-names.js", - "status" : "FAIL", - "comment" : "new failures 2022-08-08" - }, { - "filePath" : "intl402/Temporal/TimeZone/from/timezone-case-insensitive.js", - "status" : "FAIL", - "comment" : "new failures 2022-11-30" - }, { - "filePath" : "intl402/Temporal/TimeZone/from/timezone-string-legacy-non-iana.js", + "filePath" : "intl402/Temporal/PlainYearMonth/prototype/until/canonicalize-calendar.js", "status" : "FAIL", - "comment" : "new failures 2024-03-15" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/TimeZone/iana-legacy-names.js", + "filePath" : "intl402/Temporal/PlainYearMonth/prototype/until/infinity-throws-rangeerror.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "Temporal failures" }, { - "filePath" : "intl402/Temporal/TimeZone/legacy-non-iana.js", + "filePath" : "intl402/Temporal/ZonedDateTime/canonicalize-calendar.js", "status" : "FAIL", - "comment" : "new failures 2024-03-15" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/TimeZone/links-africa.js", + "filePath" : "intl402/Temporal/ZonedDateTime/compare/infinity-throws-rangeerror.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "Temporal failures" }, { - "filePath" : "intl402/Temporal/TimeZone/links-asia.js", + "filePath" : "intl402/Temporal/ZonedDateTime/construct-non-utc-non-iso.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/TimeZone/links-backward.js", + "filePath" : "intl402/Temporal/ZonedDateTime/etc-timezone.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/TimeZone/links-backzone.js", + "filePath" : "intl402/Temporal/ZonedDateTime/from/argument-valid.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/TimeZone/links-etcetera.js", + "filePath" : "intl402/Temporal/ZonedDateTime/from/canonicalize-calendar.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/TimeZone/links-europe.js", + "filePath" : "intl402/Temporal/ZonedDateTime/from/do-not-canonicalize-iana-identifiers.js", "status" : "FAIL", "comment" : "new failures 2023-10-09" }, { - "filePath" : "intl402/Temporal/TimeZone/links-northamerica.js", + "filePath" : "intl402/Temporal/ZonedDateTime/from/etc-timezone.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/TimeZone/non-canonical-utc.js", + "filePath" : "intl402/Temporal/ZonedDateTime/from/infinity-throws-rangeerror.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "Temporal failures" }, { - "filePath" : "intl402/Temporal/TimeZone/prototype/equals/argument-object.js", + "filePath" : "intl402/Temporal/ZonedDateTime/from/timezone-case-insensitive.js", "status" : "FAIL", "comment" : "new failures 2023-10-09" }, { - "filePath" : "intl402/Temporal/TimeZone/prototype/equals/argument-valid.js", + "filePath" : "intl402/Temporal/ZonedDateTime/from/zoneddatetime-sub-minute-offset.js", "status" : "FAIL", "comment" : "new failures 2023-10-09" }, { - "filePath" : "intl402/Temporal/TimeZone/prototype/equals/canonical-iana-names.js", + "filePath" : "intl402/Temporal/ZonedDateTime/iana-legacy-names.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/TimeZone/prototype/equals/canonical-not-equal.js", + "filePath" : "intl402/Temporal/ZonedDateTime/legacy-non-iana.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/TimeZone/prototype/equals/offset-and-iana.js", + "filePath" : "intl402/Temporal/ZonedDateTime/links-africa.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/TimeZone/prototype/equals/timezone-case-insensitive.js", + "filePath" : "intl402/Temporal/ZonedDateTime/links-asia.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/TimeZone/prototype/getInstantFor/infinity-throws-rangeerror.js", + "filePath" : "intl402/Temporal/ZonedDateTime/links-backward.js", "status" : "FAIL", - "comment" : "Temporal failures" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/TimeZone/prototype/getNextTransition/transition-at-instant-boundaries.js", + "filePath" : "intl402/Temporal/ZonedDateTime/links-backzone.js", "status" : "FAIL", - "comment" : "new failures 2022-08-08" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/TimeZone/prototype/getPossibleInstantsFor/infinity-throws-rangeerror.js", + "filePath" : "intl402/Temporal/ZonedDateTime/links-etcetera.js", "status" : "FAIL", - "comment" : "Temporal failures" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/ZonedDateTime/compare/infinity-throws-rangeerror.js", + "filePath" : "intl402/Temporal/ZonedDateTime/links-europe.js", "status" : "FAIL", - "comment" : "Temporal failures" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/ZonedDateTime/from/do-not-canonicalize-iana-identifiers.js", + "filePath" : "intl402/Temporal/ZonedDateTime/links-northamerica.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/ZonedDateTime/from/infinity-throws-rangeerror.js", + "filePath" : "intl402/Temporal/ZonedDateTime/non-canonical-utc.js", "status" : "FAIL", - "comment" : "Temporal failures" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/ZonedDateTime/from/timezone-case-insensitive.js", + "filePath" : "intl402/Temporal/ZonedDateTime/prototype/equals/argument-valid.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/ZonedDateTime/from/zoneddatetime-sub-minute-offset.js", + "filePath" : "intl402/Temporal/ZonedDateTime/prototype/equals/canonicalize-calendar.js", "status" : "FAIL", - "comment" : "new failures 2023-10-09" + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/ZonedDateTime/prototype/equals/infinity-throws-rangeerror.js", "status" : "FAIL", @@ -4483,6 +3491,10 @@ "filePath" : "intl402/Temporal/ZonedDateTime/prototype/equals/sub-minute-offset.js", "status" : "FAIL", "comment" : "new failures 2023-10-09" + }, { + "filePath" : "intl402/Temporal/ZonedDateTime/prototype/equals/timezone-case-insensitive.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/ZonedDateTime/prototype/era/branding.js", "status" : "FAIL", @@ -4492,53 +3504,41 @@ "status" : "FAIL", "comment" : "Temporal failures" }, { - "filePath" : "intl402/Temporal/ZonedDateTime/prototype/era/timezone-getoffsetnanosecondsfor-non-integer.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/ZonedDateTime/prototype/era/timezone-getoffsetnanosecondsfor-not-callable.js", - "status" : "FAIL", - "comment" : "Temporal failures" - }, { - "filePath" : "intl402/Temporal/ZonedDateTime/prototype/era/timezone-getoffsetnanosecondsfor-out-of-range.js", + "filePath" : "intl402/Temporal/ZonedDateTime/prototype/eraYear/branding.js", "status" : "FAIL", - "comment" : "Temporal failures" + "comment" : "Temporal tests still failing" }, { - "filePath" : "intl402/Temporal/ZonedDateTime/prototype/era/timezone-getoffsetnanosecondsfor-wrong-type.js", + "filePath" : "intl402/Temporal/ZonedDateTime/prototype/eraYear/prop-desc.js", "status" : "FAIL", "comment" : "Temporal failures" }, { - "filePath" : "intl402/Temporal/ZonedDateTime/prototype/era/validate-calendar-value.js", - "status" : "FAIL", - "comment" : "new failures 2023-02-13" - }, { - "filePath" : "intl402/Temporal/ZonedDateTime/prototype/eraYear/branding.js", + "filePath" : "intl402/Temporal/ZonedDateTime/prototype/getTimeZoneTransition/nanoseconds-subtracted-or-added-at-dst-transition.js", "status" : "FAIL", - "comment" : "Temporal tests still failing" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/ZonedDateTime/prototype/eraYear/prop-desc.js", + "filePath" : "intl402/Temporal/ZonedDateTime/prototype/getTimeZoneTransition/result-type.js", "status" : "FAIL", - "comment" : "Temporal failures" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/ZonedDateTime/prototype/eraYear/timezone-getoffsetnanosecondsfor-non-integer.js", + "filePath" : "intl402/Temporal/ZonedDateTime/prototype/getTimeZoneTransition/specific-tzdb-values.js", "status" : "FAIL", - "comment" : "Temporal failures" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/ZonedDateTime/prototype/eraYear/timezone-getoffsetnanosecondsfor-not-callable.js", + "filePath" : "intl402/Temporal/ZonedDateTime/prototype/getTimeZoneTransition/subtract-second-and-nanosecond-from-last-transition.js", "status" : "FAIL", - "comment" : "Temporal failures" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/ZonedDateTime/prototype/eraYear/timezone-getoffsetnanosecondsfor-out-of-range.js", + "filePath" : "intl402/Temporal/ZonedDateTime/prototype/getTimeZoneTransition/transition-at-instant-boundaries.js", "status" : "FAIL", - "comment" : "Temporal failures" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/ZonedDateTime/prototype/eraYear/timezone-getoffsetnanosecondsfor-wrong-type.js", + "filePath" : "intl402/Temporal/ZonedDateTime/prototype/hoursInDay/dst-midnight.js", "status" : "FAIL", - "comment" : "Temporal failures" + "comment" : "new failures 2024-08-09" }, { - "filePath" : "intl402/Temporal/ZonedDateTime/prototype/eraYear/validate-calendar-value.js", + "filePath" : "intl402/Temporal/ZonedDateTime/prototype/since/canonicalize-calendar.js", "status" : "FAIL", - "comment" : "new failures 2023-02-13" + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/ZonedDateTime/prototype/since/infinity-throws-rangeerror.js", "status" : "FAIL", @@ -4547,10 +3547,6 @@ "filePath" : "intl402/Temporal/ZonedDateTime/prototype/toLocaleString/calendar-mismatch.js", "status" : "FAIL", "comment" : "new failures 2023-05-16" - }, { - "filePath" : "intl402/Temporal/ZonedDateTime/prototype/toLocaleString/custom-time-zone-name-not-supported.js", - "status" : "FAIL", - "comment" : "new failures 2023-05-16" }, { "filePath" : "intl402/Temporal/ZonedDateTime/prototype/toLocaleString/dateStyle.js", "status" : "FAIL", @@ -4580,9 +3576,9 @@ "status" : "FAIL", "comment" : "Temporal failures" }, { - "filePath" : "intl402/Temporal/ZonedDateTime/prototype/toLocaleString/time-zone-canonicalized.js", + "filePath" : "intl402/Temporal/ZonedDateTime/prototype/until/canonicalize-calendar.js", "status" : "FAIL", - "comment" : "new failures 2023-05-16" + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/ZonedDateTime/prototype/until/infinity-throws-rangeerror.js", "status" : "FAIL", @@ -4600,9 +3596,9 @@ "status" : "FAIL", "comment" : "new failures 2023-10-09" }, { - "filePath" : "intl402/Temporal/ZonedDateTime/prototype/withPlainDate/infinity-throws-rangeerror.js", + "filePath" : "intl402/Temporal/ZonedDateTime/prototype/withCalendar/canonicalize-calendar.js", "status" : "FAIL", - "comment" : "Temporal failures" + "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/ZonedDateTime/prototype/yearOfWeek/gregory-iso-weekofyear.js", "status" : "FAIL", @@ -4611,6 +3607,14 @@ "filePath" : "intl402/Temporal/ZonedDateTime/prototype/yearOfWeek/non-iso-week-of-year.js", "status" : "FAIL", "comment" : "new failures 2024-03-15" + }, { + "filePath" : "intl402/Temporal/ZonedDateTime/timezone-case-insensitive.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" + }, { + "filePath" : "intl402/Temporal/ZonedDateTime/timezone-ids-basic.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "language/comments/S7.4_A5.js", "status" : "PASS", @@ -4704,6 +3708,10 @@ "filePath" : "staging/Intl402/Temporal/old/datetime-toLocaleString.js", "status" : "FAIL", "comment" : "new failures 2023-11-17" + }, { + "filePath" : "staging/Intl402/Temporal/old/dst-properties.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "staging/Intl402/Temporal/old/hebrew-leap-months.js", "status" : "FAIL", @@ -4720,6 +3728,10 @@ "filePath" : "staging/Intl402/Temporal/old/islamic-calendars.js", "status" : "FAIL", "comment" : "new failures 2024-01-15" + }, { + "filePath" : "staging/Intl402/Temporal/old/japanese-before-era.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "staging/Intl402/Temporal/old/japanese-era.js", "status" : "FAIL", @@ -4736,6 +3748,10 @@ "filePath" : "staging/Intl402/Temporal/old/persian-calendar.js", "status" : "FAIL", "comment" : "new failures 2024-01-15" + }, { + "filePath" : "staging/Intl402/Temporal/old/property-bags.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "staging/Intl402/Temporal/old/time-toLocaleString.js", "status" : "FAIL", @@ -4748,6 +3764,14 @@ "filePath" : "staging/Intl402/Temporal/old/yearmonth-toLocaleString.js", "status" : "FAIL", "comment" : "new failures 2023-11-17" + }, { + "filePath" : "staging/Intl402/Temporal/old/zdt-round.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" + }, { + "filePath" : "staging/Intl402/Temporal/old/zdt-with.js", + "status" : "FAIL", + "comment" : "new failures 2024-08-09" }, { "filePath" : "staging/Intl402/Temporal/old/zoneddatetime-dst-corner-cases.js", "status" : "FAIL", @@ -4764,37 +3788,9 @@ "status" : "FAIL", "comment" : "new failures 2023-11-17" }, { - "filePath" : "staging/Temporal/TimeZone/old/getInstantFor.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-17" - }, { - "filePath" : "staging/Temporal/TimeZone/old/getNextTransition.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-17" - }, { - "filePath" : "staging/Temporal/UserCalendar/old/calendar-extra-fields.js", + "filePath" : "staging/Temporal/removed-methods.js", "status" : "FAIL", - "comment" : "new failures 2023-11-17" - }, { - "filePath" : "staging/Temporal/UserCalendar/old/calendar-non-trivial-mergefields.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-17" - }, { - "filePath" : "staging/Temporal/UserCalendar/old/trivial-protocol-implementation.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-17" - }, { - "filePath" : "staging/Temporal/UserCalendar/old/trivial-subclass.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-17" - }, { - "filePath" : "staging/Temporal/ZonedDateTime/old/construction-and-properties.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-17" - }, { - "filePath" : "staging/Temporal/ZonedDateTime/old/dst-properties.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-17" + "comment" : "new failures 2024-08-09" }, { "filePath" : "staging/Temporal/ZonedDateTime/old/property-bags.js", "status" : "FAIL", @@ -4808,28 +3804,8 @@ "status" : "FAIL", "comment" : "new failures 2023-11-17" }, { - "filePath" : "staging/Temporal/ZonedDateTime/old/toPlainDate.js", + "filePath" : "staging/top-level-await/tla-hang-entry.js", "status" : "FAIL", - "comment" : "new failures 2023-11-17" - }, { - "filePath" : "staging/Temporal/ZonedDateTime/old/toPlainMonthDay.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-17" - }, { - "filePath" : "staging/Temporal/ZonedDateTime/old/toPlainYearMonth.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-17" - }, { - "filePath" : "staging/Temporal/ZonedDateTime/old/with.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-17" - }, { - "filePath" : "staging/Temporal/ZonedDateTime/old/withCalendar.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-17" - }, { - "filePath" : "staging/Temporal/ZonedDateTime/old/withTimezone.js", - "status" : "FAIL", - "comment" : "new failures 2023-11-17" + "comment" : "new failures 2024-08-09" } ] } From 96d9e1f4e834a4698d602584333257548a0e480a Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 12 Aug 2024 20:20:03 +0200 Subject: [PATCH 175/265] Report file name of any test that includes a missing test262 harness file. --- .../oracle/truffle/js/test/external/test262/Test262.java | 7 +++---- .../truffle/js/test/external/test262/Test262Runnable.java | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262.java b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262.java index 2dd238f66a6..66d9205a060 100644 --- a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262.java +++ b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262.java @@ -99,10 +99,10 @@ public Test262(SuiteConfig config) { commonOptionsExtLauncher = optionsToExtLauncherOptions(options); // sanity check: fail early if any prequel file is missing - assert getHarnessSources(false, true, Stream.empty()).length > 0; + assert getHarnessSources(false, true, Stream.empty(), "").length > 0; } - public Source[] getHarnessSources(boolean strict, boolean async, Stream includes) { + public Source[] getHarnessSources(boolean strict, boolean async, Stream includes, String context) { Stream prologStream; if (getConfig().isExtLauncher()) { prologStream = Stream.empty(); @@ -119,8 +119,7 @@ public Source[] getHarnessSources(boolean strict, boolean async, Stream try { return Source.newBuilder("js", Paths.get(harnessLocation, pfn).toFile()).build(); } catch (IOException e) { - e.printStackTrace(); - throw new RuntimeException(e); + throw new RuntimeException(e.toString() + (!context.isEmpty() ? " (" + context + ")" : ""), e); } }); diff --git a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java index bd7b9b696db..47b2293b3eb 100644 --- a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java +++ b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java @@ -354,7 +354,7 @@ public void run() { assert getIncludes(scriptCodeList).count() == 0 && !runStrict && !asyncTest; harnessSources = new Source[0]; } else { - harnessSources = ((Test262) suite).getHarnessSources(runStrict, asyncTest, getIncludes(scriptCodeList)); + harnessSources = ((Test262) suite).getHarnessSources(runStrict, asyncTest, getIncludes(scriptCodeList), testFile.getFilePath()); } boolean supported = true; From e6d875aec9e76915326fce19fd3a6f81bc9ff4fc Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 8 Aug 2024 16:23:14 +0200 Subject: [PATCH 176/265] Simplify usages of withClause(). --- .../src/com/oracle/js/parser/Parser.java | 50 +++++++++---------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java index 6034e857e26..dda7c5f6c94 100644 --- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java +++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java @@ -6981,8 +6981,8 @@ private IdentNode importedBindingIdentifier() { * *
      * ImportDeclaration :
-     *     import ImportClause FromClause ;
-     *     import ModuleSpecifier ;
+     *     import ImportClause FromClause WithClause_opt;
+     *     import ModuleSpecifier WithClause_opt;
      *     import ImportClause FromClause [no LineTerminator here] AssertClause ;
      *     import ModuleSpecifier [no LineTerminator here] AssertClause ;
      * ImportClause :
@@ -7003,19 +7003,17 @@ private void importDeclaration(ParserContextModuleNode module) {
         final long importToken = token;
         expect(IMPORT);
         if (type == STRING || type == ESCSTRING) {
-            // import ModuleSpecifier ;
+            // import ModuleSpecifier WithClause_opt;
             TruffleString moduleSpecifier = (TruffleString) getValue();
             long specifierToken = token;
             next();
             LiteralNode specifier = LiteralNode.newInstance(specifierToken, moduleSpecifier);
-            Map attributes = Map.of();
-            if (env.importAttributes && ((type == WITH) || (type == ASSERT && last != EOL))) {
-                attributes = withClause();
-            }
+            Map attributes = withClause();
+
             module.addModuleRequest(ModuleRequest.create(moduleSpecifier, attributes));
             module.addImport(new ImportNode(importToken, Token.descPosition(importToken), finish, specifier));
         } else {
-            // import ImportClause FromClause ;
+            // import ImportClause FromClause WithClause_opt;
             final List importEntries = new ArrayList<>();
             final ImportClauseNode importClause;
             final long startToken = token;
@@ -7055,10 +7053,8 @@ private void importDeclaration(ParserContextModuleNode module) {
             }
 
             FromNode fromNode = fromClause();
-            Map attributes = Map.of();
-            if (env.importAttributes && ((type == WITH) || (type == ASSERT && last != EOL))) {
-                attributes = withClause();
-            }
+            Map attributes = withClause();
+
             module.addImport(new ImportNode(importToken, Token.descPosition(importToken), finish, importClause, fromNode));
             TruffleString moduleSpecifier = fromNode.getModuleSpecifier().getValue();
             ModuleRequest moduleRequest = ModuleRequest.create(moduleSpecifier, attributes);
@@ -7071,7 +7067,7 @@ private void importDeclaration(ParserContextModuleNode module) {
     }
 
     /**
-     * Parse assert clause.
+     * Parse optional with clause (or legacy assert clause).
      *
      * 
      *     AttributesKeyword { }
@@ -7079,12 +7075,14 @@ private void importDeclaration(ParserContextModuleNode module) {
      * 
*/ private Map withClause() { - assert (type == ASSERT || type == WITH); - next(); - expect(LBRACE); - Map entries = withEntries(); - expect(RBRACE); - return entries; + Map attributes = Map.of(); + if (env.importAttributes && ((type == WITH) || (type == ASSERT && last != EOL))) { + next(); + expect(LBRACE); + attributes = withEntries(); + expect(RBRACE); + } + return attributes; } /** @@ -7232,7 +7230,7 @@ private FromNode fromClause() { * *
      * ExportDeclaration :
-     *     export ExportFromClause FromClause ;
+     *     export ExportFromClause FromClause WithClause_opt ;
      *     export ExportFromClause FromClause [no LineTerminator here] AssertClause;
      *     export NamedExports ;
      *     export VariableStatement
@@ -7244,7 +7242,6 @@ private FromNode fromClause() {
      */
     private void exportDeclaration(ParserContextModuleNode module) {
         final long exportToken = token;
-        Map attributes = Map.of();
         expect(EXPORT);
         final boolean yield = false;
         final boolean await = isTopLevelAwait();
@@ -7257,9 +7254,8 @@ private void exportDeclaration(ParserContextModuleNode module) {
                     exportName = moduleExportName();
                 }
                 FromNode from = fromClause();
-                if (env.importAttributes && ((type == WITH) || (type == ASSERT && last != EOL))) {
-                    attributes = withClause();
-                }
+                Map attributes = withClause();
+
                 TruffleString moduleRequest = from.getModuleSpecifier().getValue();
                 module.addModuleRequest(ModuleRequest.create(moduleRequest, attributes));
                 module.addExport(new ExportNode(exportToken, Token.descPosition(exportToken), finish, exportName, from, attributes));
@@ -7269,11 +7265,11 @@ private void exportDeclaration(ParserContextModuleNode module) {
             case LBRACE: {
                 NamedExportsNode exportClause = namedExports();
                 FromNode from = null;
+                Map attributes = Map.of();
                 if (type == FROM) {
                     from = fromClause();
-                    if (env.importAttributes && ((type == WITH) || (type == ASSERT && last != EOL))) {
-                        attributes = withClause();
-                    }
+                    attributes = withClause();
+
                     TruffleString moduleRequest = from.getModuleSpecifier().getValue();
                     module.addModuleRequest(ModuleRequest.create(moduleRequest, attributes));
                 } else {

From 90f4a05865aee7d3b51a7c247ace226639170b6f Mon Sep 17 00:00:00 2001
From: Andreas Woess 
Date: Thu, 8 Aug 2024 16:36:05 +0200
Subject: [PATCH 177/265] Remove unused ScriptEnvironment.dumpOnError.

---
 .../src/com/oracle/js/parser/Parser.java      |  8 ----
 .../oracle/js/parser/ScriptEnvironment.java   | 47 +++++++------------
 .../js/parser/GraalJSParserHelper.java        |  4 --
 .../truffle/js/runtime/JSParserOptions.java   |  8 ++--
 4 files changed, 19 insertions(+), 48 deletions(-)

diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
index dda7c5f6c94..85f403eb151 100644
--- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
+++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
@@ -700,10 +700,6 @@ public FunctionNode parseFunctionBody(boolean generator, boolean async) {
     private void handleParseException(final ParserException e) {
         // Issue message.
         errors.error(e);
-
-        if (env.dumpOnError) {
-            e.printStackTrace(env.getErr());
-        }
     }
 
     /**
@@ -713,10 +709,6 @@ private void recover(final ParserException e) {
         if (e != null) {
             // Issue message.
             errors.error(e);
-
-            if (env.dumpOnError) {
-                e.printStackTrace(env.getErr());
-            }
         }
 
         // Skip to a recovery point.
diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ScriptEnvironment.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ScriptEnvironment.java
index 8c9ad321ee5..23ad5bacdb3 100644
--- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ScriptEnvironment.java
+++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ScriptEnvironment.java
@@ -41,8 +41,6 @@
 
 package com.oracle.js.parser;
 
-import java.io.PrintWriter;
-
 /**
  * Parser environment consists of command line options, and output and error writers, etc.
  */
@@ -60,15 +58,9 @@ public final class ScriptEnvironment {
     public static final int ES_2024 = 15;
     public static final int ES_STAGING = Integer.MAX_VALUE;
 
-    /** Error writer for this environment */
-    private final PrintWriter err;
-
     /** Accept "const" keyword and treat it as variable. Interim feature */
     final boolean constAsVar;
 
-    /** Display stack trace upon error, default is false */
-    final boolean dumpOnError;
-
     /** Empty statements should be preserved in the AST */
     final boolean emptyStatements;
 
@@ -135,14 +127,22 @@ public enum FunctionStatementBehavior {
     /** Are V8 intrinsics supported? */
     final boolean v8Intrinsics;
 
-    private ScriptEnvironment(boolean strict, int ecmaScriptVersion, boolean emptyStatements, boolean syntaxExtensions, boolean scripting, boolean shebang,
-                    boolean constAsVar, boolean allowBigInt, boolean annexB, boolean classFields, boolean importAttributes, boolean privateFieldsIn, boolean topLevelAwait, boolean v8Intrinsics,
-                    FunctionStatementBehavior functionStatementBehavior,
-                    PrintWriter dumpOnError) {
-        this.err = dumpOnError;
-
+    public ScriptEnvironment(boolean strict,
+                    int ecmaScriptVersion,
+                    boolean emptyStatements,
+                    boolean syntaxExtensions,
+                    boolean scripting,
+                    boolean shebang,
+                    boolean constAsVar,
+                    boolean allowBigInt,
+                    boolean annexB,
+                    boolean classFields,
+                    boolean importAttributes,
+                    boolean privateFieldsIn,
+                    boolean topLevelAwait,
+                    boolean v8Intrinsics,
+                    FunctionStatementBehavior functionStatementBehavior) {
         this.constAsVar = constAsVar;
-        this.dumpOnError = dumpOnError != null;
         this.emptyStatements = emptyStatements;
         this.functionStatement = functionStatementBehavior;
         this.syntaxExtensions = syntaxExtensions;
@@ -159,15 +159,6 @@ private ScriptEnvironment(boolean strict, int ecmaScriptVersion, boolean emptySt
         this.v8Intrinsics = v8Intrinsics;
     }
 
-    /**
-     * Get the error stream for this environment
-     *
-     * @return error print writer
-     */
-    PrintWriter getErr() {
-        return err;
-    }
-
     public boolean isStrict() {
         return strict;
     }
@@ -193,7 +184,6 @@ public static final class Builder {
         private boolean topLevelAwait = false;
         private boolean v8Intrinsics = false;
         private FunctionStatementBehavior functionStatementBehavior = FunctionStatementBehavior.ERROR;
-        private PrintWriter dumpOnError;
 
         private Builder() {
         }
@@ -273,14 +263,9 @@ public Builder functionStatementBehavior(FunctionStatementBehavior functionState
             return this;
         }
 
-        public Builder dumpOnError(PrintWriter dumpOnError) {
-            this.dumpOnError = dumpOnError;
-            return this;
-        }
-
         public ScriptEnvironment build() {
             return new ScriptEnvironment(strict, ecmaScriptVersion, emptyStatements, syntaxExtensions, scripting, shebang, constAsVar, allowBigInt, annexB,
-                            classFields, importAttributes, privateFieldsIn, topLevelAwait, v8Intrinsics, functionStatementBehavior, dumpOnError);
+                            classFields, importAttributes, privateFieldsIn, topLevelAwait, v8Intrinsics, functionStatementBehavior);
         }
     }
 }
diff --git a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSParserHelper.java b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSParserHelper.java
index 344b0d2bc05..0105f895f6b 100644
--- a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSParserHelper.java
+++ b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSParserHelper.java
@@ -40,7 +40,6 @@
  */
 package com.oracle.truffle.js.parser;
 
-import java.io.PrintWriter;
 import java.util.List;
 import java.util.function.Function;
 
@@ -205,9 +204,6 @@ private static ScriptEnvironment makeScriptEnvironment(JSParserOptions parserOpt
         } else {
             builder.functionStatementBehavior(FunctionStatementBehavior.ACCEPT);
         }
-        if (parserOptions.dumpOnError()) {
-            builder.dumpOnError(new PrintWriter(System.err, true));
-        }
         return builder.build();
     }
 
diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSParserOptions.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSParserOptions.java
index 408ed82846c..1c96d8c6335 100644
--- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSParserOptions.java
+++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSParserOptions.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * The Universal Permissive License (UPL), Version 1.0
@@ -54,7 +54,6 @@ public record JSParserOptions(boolean strict,
                 boolean syntaxExtensions,
                 boolean constAsVar,
                 boolean functionStatementError,
-                boolean dumpOnError,
                 boolean emptyStatements,
                 boolean annexB,
                 boolean allowBigInt,
@@ -72,7 +71,6 @@ public static JSParserOptions fromLanguageOptions(JSLanguageOptions options) {
         boolean syntaxExtensions = options.syntaxExtensions();
         boolean constAsVar = options.constAsVar();
         boolean functionStatementError = options.functionStatementError();
-        boolean dumpOnError = false;
         boolean emptyStatements = false;
         boolean annexB = options.annexB();
         boolean allowBigInt = options.bigInt();
@@ -81,13 +79,13 @@ public static JSParserOptions fromLanguageOptions(JSLanguageOptions options) {
         boolean privateFieldsIn = options.privateFieldsIn();
         boolean topLevelAwait = options.topLevelAwait();
         boolean v8Intrinsics = options.v8Intrinsics();
-        return new JSParserOptions(strict, scripting, shebang, ecmaScriptVersion, syntaxExtensions, constAsVar, functionStatementError, dumpOnError, emptyStatements, annexB, allowBigInt,
+        return new JSParserOptions(strict, scripting, shebang, ecmaScriptVersion, syntaxExtensions, constAsVar, functionStatementError, emptyStatements, annexB, allowBigInt,
                         classFields, importAttributes, privateFieldsIn, topLevelAwait, v8Intrinsics);
     }
 
     public JSParserOptions withStrict(@SuppressWarnings("hiding") boolean strict) {
         if (strict != this.strict) {
-            return new JSParserOptions(strict, scripting, shebang, ecmaScriptVersion, syntaxExtensions, constAsVar, functionStatementError, dumpOnError, emptyStatements, annexB, allowBigInt,
+            return new JSParserOptions(strict, scripting, shebang, ecmaScriptVersion, syntaxExtensions, constAsVar, functionStatementError, emptyStatements, annexB, allowBigInt,
                             classFields, importAttributes, privateFieldsIn, topLevelAwait, v8Intrinsics);
         }
         return this;

From fc63ce0b1bfd6368b629bd3564578367b94dbe1f Mon Sep 17 00:00:00 2001
From: Andreas Woess 
Date: Thu, 8 Aug 2024 17:05:27 +0200
Subject: [PATCH 178/265] Separate legacy import-assertions from
 import-attributes option.

---
 .../src/com/oracle/js/parser/Parser.java      |  4 +-
 .../oracle/js/parser/ScriptEnvironment.java   | 13 ++++-
 .../js/parser/GraalJSParserHelper.java        |  1 +
 .../truffle/js/parser/GraalJSTranslator.java  |  4 +-
 .../external/test262/Test262Runnable.java     |  5 +-
 .../test/external/testv8/TestV8Runnable.java  |  1 +
 .../js/module/import_call_assertion_error.mjs |  4 +-
 .../module/import_call_attributes_error.mjs   | 47 +++++++++++++++++++
 .../ImportAssertionsWithCustomFsTest.java     |  6 +--
 .../js/nodes/promise/ImportCallNode.java      | 15 +++---
 .../oracle/truffle/js/runtime/JSContext.java  |  2 +-
 .../truffle/js/runtime/JSContextOptions.java  | 10 ++++
 .../truffle/js/runtime/JSLanguageOptions.java |  3 ++
 .../truffle/js/runtime/JSParserOptions.java   |  6 ++-
 .../oracle/truffle/trufflenode/Options.java   |  6 ++-
 15 files changed, 106 insertions(+), 21 deletions(-)
 create mode 100644 graal-js/src/com.oracle.truffle.js.test/js/module/import_call_attributes_error.mjs

diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
index 85f403eb151..b5eb006a48f 100644
--- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
+++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
@@ -5106,7 +5106,7 @@ private Expression importExpression(boolean yield, boolean await) {
             next();
             List arguments = new ArrayList<>();
             arguments.add(assignmentExpression(true, yield, await));
-            if (env.importAttributes && type == COMMARIGHT) {
+            if (type == COMMARIGHT && (env.importAttributes || env.importAssertions)) {
                 next();
                 if (type != RPAREN) {
                     arguments.add(assignmentExpression(true, yield, await));
@@ -7068,7 +7068,7 @@ private void importDeclaration(ParserContextModuleNode module) {
      */
     private Map withClause() {
         Map attributes = Map.of();
-        if (env.importAttributes && ((type == WITH) || (type == ASSERT && last != EOL))) {
+        if ((env.importAttributes && type == WITH) || (env.importAssertions && type == ASSERT && last != EOL)) {
             next();
             expect(LBRACE);
             attributes = withEntries();
diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ScriptEnvironment.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ScriptEnvironment.java
index 23ad5bacdb3..17bdb186e63 100644
--- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ScriptEnvironment.java
+++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ScriptEnvironment.java
@@ -118,6 +118,9 @@ public enum FunctionStatementBehavior {
     /** Are import attributes enabled. */
     final boolean importAttributes;
 
+    /** Are legacy import assertions enabled. */
+    final boolean importAssertions;
+
     /** Is private field in enabled */
     final boolean privateFieldsIn;
 
@@ -138,6 +141,7 @@ public ScriptEnvironment(boolean strict,
                     boolean annexB,
                     boolean classFields,
                     boolean importAttributes,
+                    boolean importAssertions,
                     boolean privateFieldsIn,
                     boolean topLevelAwait,
                     boolean v8Intrinsics,
@@ -154,6 +158,7 @@ public ScriptEnvironment(boolean strict,
         this.annexB = annexB;
         this.classFields = classFields;
         this.importAttributes = importAttributes;
+        this.importAssertions = importAssertions;
         this.privateFieldsIn = privateFieldsIn;
         this.topLevelAwait = topLevelAwait;
         this.v8Intrinsics = v8Intrinsics;
@@ -180,6 +185,7 @@ public static final class Builder {
         private boolean annexB = true;
         private boolean classFields = true;
         private boolean importAttributes = false;
+        private boolean importAssertions = false;
         private boolean privateFieldsIn = false;
         private boolean topLevelAwait = false;
         private boolean v8Intrinsics = false;
@@ -243,6 +249,11 @@ public Builder importAttributes(boolean importAttributes) {
             return this;
         }
 
+        public Builder importAssertions(boolean importAssertions) {
+            this.importAssertions = importAssertions;
+            return this;
+        }
+
         public Builder privateFieldsIn(boolean privateFieldsIn) {
             this.privateFieldsIn = privateFieldsIn;
             return this;
@@ -265,7 +276,7 @@ public Builder functionStatementBehavior(FunctionStatementBehavior functionState
 
         public ScriptEnvironment build() {
             return new ScriptEnvironment(strict, ecmaScriptVersion, emptyStatements, syntaxExtensions, scripting, shebang, constAsVar, allowBigInt, annexB,
-                            classFields, importAttributes, privateFieldsIn, topLevelAwait, v8Intrinsics, functionStatementBehavior);
+                            classFields, importAttributes, importAssertions, privateFieldsIn, topLevelAwait, v8Intrinsics, functionStatementBehavior);
         }
     }
 }
diff --git a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSParserHelper.java b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSParserHelper.java
index 0105f895f6b..21019e1abd7 100644
--- a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSParserHelper.java
+++ b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSParserHelper.java
@@ -196,6 +196,7 @@ private static ScriptEnvironment makeScriptEnvironment(JSParserOptions parserOpt
         builder.annexB(parserOptions.annexB());
         builder.classFields(parserOptions.classFields());
         builder.importAttributes(parserOptions.importAttributes());
+        builder.importAssertions(parserOptions.importAssertions());
         builder.privateFieldsIn(parserOptions.privateFieldsIn());
         builder.topLevelAwait(parserOptions.topLevelAwait());
         builder.v8Intrinsics(parserOptions.v8Intrinsics());
diff --git a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSTranslator.java b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSTranslator.java
index 5465f50d71c..aaf70c59119 100644
--- a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSTranslator.java
+++ b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSTranslator.java
@@ -2659,10 +2659,10 @@ private JavaScriptNode createCallDirectSuper(JavaScriptNode function, JavaScript
     }
 
     private JavaScriptNode createImportCallNode(JavaScriptNode[] args) {
-        assert args.length == 1 || (context.getLanguageOptions().importAttributes() && args.length == 2);
-        if (context.getLanguageOptions().importAttributes() && args.length == 2) {
+        if (args.length == 2 && (context.getLanguageOptions().importAttributes() || context.getLanguageOptions().importAssertions())) {
             return factory.createImportCall(context, args[0], activeScriptOrModule, args[1]);
         }
+        assert args.length == 1 : args.length;
         return factory.createImportCall(context, args[0], activeScriptOrModule);
     }
 
diff --git a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java
index 47b2293b3eb..53d0fff7c20 100644
--- a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java
+++ b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java
@@ -310,9 +310,12 @@ public void run() {
         if (features.contains("error-cause")) {
             extraOptions.put(JSContextOptions.ERROR_CAUSE_NAME, "true");
         }
-        if (features.contains("import-attributes") || features.contains("import-assertions")) {
+        if (features.contains("import-attributes")) {
             extraOptions.put(JSContextOptions.IMPORT_ATTRIBUTES_NAME, "true");
         }
+        if (features.contains("import-assertions")) {
+            extraOptions.put(JSContextOptions.IMPORT_ASSERTIONS_NAME, "true");
+        }
         if (features.contains("json-modules")) {
             extraOptions.put(JSContextOptions.JSON_MODULES_NAME, "true");
         }
diff --git a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/testv8/TestV8Runnable.java b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/testv8/TestV8Runnable.java
index 42ac98712c8..57a9e7b13d2 100644
--- a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/testv8/TestV8Runnable.java
+++ b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/testv8/TestV8Runnable.java
@@ -190,6 +190,7 @@ public void run() {
         }
         if (flags.contains(HARMONY_IMPORT_ASSERTIONS) || flags.contains(HARMONY_IMPORT_ATTRIBUTES)) {
             extraOptions.put(JSContextOptions.IMPORT_ATTRIBUTES_NAME, "true");
+            extraOptions.put(JSContextOptions.IMPORT_ASSERTIONS_NAME, "true");
             extraOptions.put(JSContextOptions.JSON_MODULES_NAME, "true");
         }
         if (flags.contains(HARMONY_ITERATOR_HELPERS)) {
diff --git a/graal-js/src/com.oracle.truffle.js.test/js/module/import_call_assertion_error.mjs b/graal-js/src/com.oracle.truffle.js.test/js/module/import_call_assertion_error.mjs
index a99389e09a5..52c1604c51e 100644
--- a/graal-js/src/com.oracle.truffle.js.test/js/module/import_call_assertion_error.mjs
+++ b/graal-js/src/com.oracle.truffle.js.test/js/module/import_call_assertion_error.mjs
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl.
@@ -8,7 +8,7 @@
 /**
  * Tests that import calls with invalid options/assertions throw a TypeError.
  *
- * @option import-attributes=true
+ * @option import-assertions=true
  */
 
 function shouldHaveThrown(err) {
diff --git a/graal-js/src/com.oracle.truffle.js.test/js/module/import_call_attributes_error.mjs b/graal-js/src/com.oracle.truffle.js.test/js/module/import_call_attributes_error.mjs
new file mode 100644
index 00000000000..1a98215f08b
--- /dev/null
+++ b/graal-js/src/com.oracle.truffle.js.test/js/module/import_call_attributes_error.mjs
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl.
+ */
+
+/**
+ * Tests that import calls with invalid options/attributes throw a TypeError.
+ *
+ * @option import-attributes=true
+ */
+
+function shouldHaveThrown(err) {
+    throw new Error(`should have thrown ${err}`);
+}
+
+const from = './import_call_assertion_error_imported.mjs';
+
+try {
+    // The second argument to import() must be an object
+    await import(from, 42);
+    shouldHaveThrown(TypeError);
+} catch (e) {
+    if (!(e instanceof TypeError)) throw e;
+}
+
+try {
+    // The 'with' option must be an object
+    await import(from, {with: 42});
+    shouldHaveThrown(TypeError);
+} catch (e) {
+    if (!(e instanceof TypeError)) throw e;
+}
+
+try {
+    // Import attribute value must be a string
+    await import(from, {with: {attr: 42}});
+    shouldHaveThrown(TypeError);
+} catch (e) {
+    if (!(e instanceof TypeError)) throw e;
+}
+
+// Valid
+await import(from, {});
+await import(from, {with: {}});
+await import(from, {with: {attr: 'value'}});
diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/ImportAssertionsWithCustomFsTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/ImportAssertionsWithCustomFsTest.java
index 83f007c2c86..4840ad07862 100644
--- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/ImportAssertionsWithCustomFsTest.java
+++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/ImportAssertionsWithCustomFsTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * The Universal Permissive License (UPL), Version 1.0
@@ -88,7 +88,7 @@ private static void executeTest(TestTuple source, String importName) throws IOEx
             try (Context context = JSTest.newContextBuilder().allowIO(ioAccess).out(out).//
                             option(JSContextOptions.CONSOLE_NAME, "true").//
                             option(JSContextOptions.INTEROP_COMPLETE_PROMISES_NAME, "false").//
-                            option(JSContextOptions.IMPORT_ATTRIBUTES_NAME, "true").//
+                            option(JSContextOptions.IMPORT_ASSERTIONS_NAME, "true").//
                             option(JSContextOptions.JSON_MODULES_NAME, "true").//
                             build()) {
                 Value asyncFn = context.eval(JavaScriptLanguage.ID, source.statement);
@@ -97,7 +97,7 @@ private static void executeTest(TestTuple source, String importName) throws IOEx
             Assert.assertEquals(source.expectedValue + "\n", out.toString());
         } else {
             try (Context context = JSTest.newContextBuilder().allowIO(ioAccess).//
-                            option(JSContextOptions.IMPORT_ATTRIBUTES_NAME, "true").//
+                            option(JSContextOptions.IMPORT_ASSERTIONS_NAME, "true").//
                             option(JSContextOptions.JSON_MODULES_NAME, "true").//
                             build()) {
                 Value v = context.eval(Source.newBuilder(JavaScriptLanguage.ID, source.statement, "exec.mjs").build());
diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java
index 7bfcc875ef9..84add74e086 100644
--- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java
+++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java
@@ -139,7 +139,7 @@ public static ImportCallNode create(JSContext context) {
     public Object execute(VirtualFrame frame) {
         ScriptOrModule referencingScriptOrModule = activeScriptOrModule;
         Object specifier = argRefNode.execute(frame);
-        if (context.getLanguageOptions().importAttributes() && optionsRefNode != null) {
+        if (optionsRefNode != null) {
             return executeAttributes(frame, referencingScriptOrModule, specifier);
         } else {
             return executeWithoutAttributes(referencingScriptOrModule, specifier);
@@ -179,20 +179,23 @@ private Object executeAttributes(VirtualFrame frame, ScriptOrModule referencingS
             if (!JSRuntime.isObject(options)) {
                 return rejectPromiseWithTypeError(promiseCapability, "The second argument to import() must be an object");
             }
-            Object attributesObj;
+            Object attributesObj = Undefined.instance;
             try {
-                attributesObj = getWithNode.getValue(options);
+                if (context.getLanguageOptions().importAttributes()) {
+                    attributesObj = getWithNode.getValue(options);
+                }
                 if (attributesObj == Undefined.instance) {
-                    attributesObj = getAssertNode.getValue(options);
+                    if (context.getLanguageOptions().importAssertions()) {
+                        attributesObj = getAssertNode.getValue(options);
+                    }
                 }
             } catch (AbstractTruffleException ex) {
                 return rejectPromise(promiseCapability, ex);
             }
             if (attributesObj != Undefined.instance) {
-                if (!JSRuntime.isObject(attributesObj)) {
+                if (!(attributesObj instanceof JSObject obj)) {
                     return rejectPromiseWithTypeError(promiseCapability, "The 'assert' option must be an object");
                 }
-                JSDynamicObject obj = (JSDynamicObject) attributesObj;
                 UnmodifiableArrayList keys;
                 try {
                     keys = enumerableOwnPropertyNamesNode.execute(obj);
diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContext.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContext.java
index 2fe0552dcfe..9f3e8160924 100644
--- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContext.java
+++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContext.java
@@ -760,7 +760,7 @@ protected JSContext(Evaluator evaluator, JavaScriptLanguage lang, JSLanguageOpti
         this.regexOptions = createRegexOptions(languageOptions);
         this.regexValidateOptions = regexOptions.isEmpty() ? REGEX_OPTION_VALIDATE : REGEX_OPTION_VALIDATE + "," + regexOptions;
 
-        this.supportedImportAttributes = languageOptions.importAttributes() ? Set.of(TYPE_IMPORT_ATTRIBUTE) : Set.of();
+        this.supportedImportAttributes = (languageOptions.importAttributes() || languageOptions.importAssertions()) ? Set.of(TYPE_IMPORT_ATTRIBUTE) : Set.of();
     }
 
     public final Evaluator getEvaluator() {
diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java
index 62124ec01cc..74322588d49 100644
--- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java
+++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java
@@ -638,6 +638,11 @@ public String toString() {
     public static final OptionKey IMPORT_ATTRIBUTES = new OptionKey<>(false);
     @CompilationFinal private boolean importAttributes;
 
+    public static final String IMPORT_ASSERTIONS_NAME = JS_OPTION_PREFIX + "import-assertions";
+    @Option(name = IMPORT_ASSERTIONS_NAME, category = OptionCategory.USER, help = "Enable legacy import assertions") //
+    public static final OptionKey IMPORT_ASSERTIONS = new OptionKey<>(false);
+    @CompilationFinal private boolean importAssertions;
+
     public static final String JSON_MODULES_NAME = JS_OPTION_PREFIX + "json-modules";
     @Option(name = JSON_MODULES_NAME, category = OptionCategory.USER, help = "Enable loading of json modules") //
     public static final OptionKey JSON_MODULES = new OptionKey<>(false);
@@ -788,6 +793,7 @@ private void cacheOptions(SandboxPolicy sandboxPolicy) {
         this.operatorOverloading = readBooleanOption(OPERATOR_OVERLOADING);
         this.errorCause = ERROR_CAUSE.hasBeenSet(optionValues) ? readBooleanOption(ERROR_CAUSE) : getEcmaScriptVersion() >= JSConfig.ECMAScript2022;
         this.importAttributes = readBooleanOption(IMPORT_ATTRIBUTES);
+        this.importAssertions = readBooleanOption(IMPORT_ASSERTIONS);
         this.jsonModules = readBooleanOption(JSON_MODULES);
         this.wasmBigInt = readBooleanOption(WASM_BIG_INT);
         this.esmEvalReturnsExports = readBooleanOption(ESM_EVAL_RETURNS_EXPORTS);
@@ -1209,6 +1215,10 @@ public boolean isImportAttributes() {
         return importAttributes;
     }
 
+    public boolean isImportAssertions() {
+        return importAssertions;
+    }
+
     public boolean isJsonModules() {
         return jsonModules;
     }
diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSLanguageOptions.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSLanguageOptions.java
index dedec1c1799..7cd8e03b4c6 100644
--- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSLanguageOptions.java
+++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSLanguageOptions.java
@@ -112,6 +112,7 @@ public record JSLanguageOptions(
                 boolean operatorOverloading,
                 boolean errorCause,
                 boolean importAttributes,
+                boolean importAssertions,
                 boolean jsonModules,
                 boolean wasmBigInt,
                 boolean esmEvalReturnsExports,
@@ -188,6 +189,7 @@ public static JSLanguageOptions fromContextOptions(JSContextOptions options) {
         boolean operatorOverloading = options.isOperatorOverloading();
         boolean errorCause = options.isErrorCauseEnabled();
         boolean importAttributes = options.isImportAttributes();
+        boolean importAssertions = options.isImportAssertions();
         boolean jsonModules = options.isJsonModules();
         boolean wasmBigInt = options.isWasmBigInt();
         boolean esmEvalReturnsExports = options.isEsmEvalReturnsExports();
@@ -271,6 +273,7 @@ public static JSLanguageOptions fromContextOptions(JSContextOptions options) {
                         operatorOverloading,
                         errorCause,
                         importAttributes,
+                        importAssertions,
                         jsonModules,
                         wasmBigInt,
                         esmEvalReturnsExports,
diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSParserOptions.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSParserOptions.java
index 1c96d8c6335..35bda03c174 100644
--- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSParserOptions.java
+++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSParserOptions.java
@@ -59,6 +59,7 @@ public record JSParserOptions(boolean strict,
                 boolean allowBigInt,
                 boolean classFields,
                 boolean importAttributes,
+                boolean importAssertions,
                 boolean privateFieldsIn,
                 boolean topLevelAwait,
                 boolean v8Intrinsics) {
@@ -76,17 +77,18 @@ public static JSParserOptions fromLanguageOptions(JSLanguageOptions options) {
         boolean allowBigInt = options.bigInt();
         boolean classFields = options.classFields();
         boolean importAttributes = options.importAttributes();
+        boolean importAssertions = options.importAssertions();
         boolean privateFieldsIn = options.privateFieldsIn();
         boolean topLevelAwait = options.topLevelAwait();
         boolean v8Intrinsics = options.v8Intrinsics();
         return new JSParserOptions(strict, scripting, shebang, ecmaScriptVersion, syntaxExtensions, constAsVar, functionStatementError, emptyStatements, annexB, allowBigInt,
-                        classFields, importAttributes, privateFieldsIn, topLevelAwait, v8Intrinsics);
+                        classFields, importAttributes, importAssertions, privateFieldsIn, topLevelAwait, v8Intrinsics);
     }
 
     public JSParserOptions withStrict(@SuppressWarnings("hiding") boolean strict) {
         if (strict != this.strict) {
             return new JSParserOptions(strict, scripting, shebang, ecmaScriptVersion, syntaxExtensions, constAsVar, functionStatementError, emptyStatements, annexB, allowBigInt,
-                            classFields, importAttributes, privateFieldsIn, topLevelAwait, v8Intrinsics);
+                            classFields, importAttributes, importAssertions, privateFieldsIn, topLevelAwait, v8Intrinsics);
         }
         return this;
     }
diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/Options.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/Options.java
index 722be4ecc07..ea7efadc7e4 100644
--- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/Options.java
+++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/Options.java
@@ -246,10 +246,14 @@ protected List preprocessArguments(List arguments, Map
Date: Tue, 13 Aug 2024 23:20:41 +0200
Subject: [PATCH 179/265] Test both import assertions and attributes.

---
 .../ImportAssertionsWithCustomFsTest.java     | 114 ++++++++++++++----
 1 file changed, 91 insertions(+), 23 deletions(-)

diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/ImportAssertionsWithCustomFsTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/ImportAssertionsWithCustomFsTest.java
index 4840ad07862..457e568fb6d 100644
--- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/ImportAssertionsWithCustomFsTest.java
+++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/ImportAssertionsWithCustomFsTest.java
@@ -53,8 +53,10 @@
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.attribute.FileAttribute;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -65,30 +67,45 @@
 import org.graalvm.polyglot.io.IOAccess;
 import org.junit.Assert;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
 
 import com.oracle.truffle.js.lang.JavaScriptLanguage;
 import com.oracle.truffle.js.runtime.JSContextOptions;
 import com.oracle.truffle.js.test.JSTest;
 
+@RunWith(Parameterized.class)
 public class ImportAssertionsWithCustomFsTest {
 
-    private static void executeTest(TestTuple source) throws IOException {
+    @Parameters(name = "{0}")
+    public static List data() {
+        return Arrays.asList("assert", "with");
+    }
+
+    @Parameter(value = 0) public String keyword;
+
+    private void executeTest(TestTuple source) throws IOException {
         executeTest(source, "./test.js");
     }
 
-    private static void executeTest(TestTuple source, String importName) throws IOException {
+    private void executeTest(TestTuple source, String importName) throws IOException {
         TestFileSystem fs = new TestFileSystem();
         fs.add(importName, source.fileContent);
         if (source.additionalModuleName != null) {
             fs.add(source.additionalModuleName, source.additionalModuleBody);
         }
+        String importOptionName = "with".equals(keyword)
+                        ? JSContextOptions.IMPORT_ATTRIBUTES_NAME
+                        : JSContextOptions.IMPORT_ASSERTIONS_NAME;
         IOAccess ioAccess = IOAccess.newBuilder().fileSystem(fs).build();
         if (source.isAsync) {
             ByteArrayOutputStream out = new ByteArrayOutputStream();
             try (Context context = JSTest.newContextBuilder().allowIO(ioAccess).out(out).//
                             option(JSContextOptions.CONSOLE_NAME, "true").//
                             option(JSContextOptions.INTEROP_COMPLETE_PROMISES_NAME, "false").//
-                            option(JSContextOptions.IMPORT_ASSERTIONS_NAME, "true").//
+                            option(importOptionName, "true").//
                             option(JSContextOptions.JSON_MODULES_NAME, "true").//
                             build()) {
                 Value asyncFn = context.eval(JavaScriptLanguage.ID, source.statement);
@@ -97,7 +114,7 @@ private static void executeTest(TestTuple source, String importName) throws IOEx
             Assert.assertEquals(source.expectedValue + "\n", out.toString());
         } else {
             try (Context context = JSTest.newContextBuilder().allowIO(ioAccess).//
-                            option(JSContextOptions.IMPORT_ASSERTIONS_NAME, "true").//
+                            option(importOptionName, "true").//
                             option(JSContextOptions.JSON_MODULES_NAME, "true").//
                             build()) {
                 Value v = context.eval(Source.newBuilder(JavaScriptLanguage.ID, source.statement, "exec.mjs").build());
@@ -106,27 +123,48 @@ private static void executeTest(TestTuple source, String importName) throws IOEx
         }
     }
 
-    private static void executeStatements(String assertVal) throws IOException {
+    private void executeStatements(String assertVal) throws IOException {
         for (TestTuple statement : getTestTuples(assertVal)) {
             executeTest(statement);
         }
     }
 
-    private static TestTuple[] getTestTuples(String assertVal) {
+    private TestTuple[] getTestTuples(String assertVal) {
         return getTestTuples(assertVal, "./test.js");
     }
 
-    private static TestTuple[] getTestTuples(String assertVal, String importName) {
+    private TestTuple[] getTestTuples(String assertVal, String importName) {
         TestTuple[] testTuples = new TestTuple[5];
-        testTuples[0] = new TestTuple("import { val } from '" + importName + "' assert " + assertVal + "; val;", "export const val = 'value';", "value");
-        testTuples[1] = new TestTuple("import json from '" + importName + "' assert " + assertVal + "; json.val;", "let json = { val: 'value' }; export { json as default };", "value");
-        testTuples[2] = new TestTuple("import { val } from '" + importName + "'; val;", "export { val } from './test2.js' assert " + assertVal + ";", "value", "./test2.js",
+        testTuples[0] = new TestTuple(
+                        "import { val } from '" + importName + "' " + keyword + " " + assertVal + "; val;",
                         "export const val = 'value';",
-                        false);
-        testTuples[3] = new TestTuple("(async function () { let {default:json} = await import('" + importName + "', { assert: " + assertVal + " } ); console.log(json.val); });",
-                        "let json = { val: 'value' }; export { json as default };", "value", true);
-        testTuples[4] = new TestTuple("(async function () { let {default:json} = await import('" + importName + "', { assert: " + assertVal + " }, ); console.log(json.val);});",
-                        "let json = { val: 'value' }; export { json as default };", "value", true);
+                        "value");
+        testTuples[1] = new TestTuple(
+                        "import json from '" + importName + "' " + keyword + " " + assertVal + "; json.val;",
+                        "let json = { val: 'value' }; export { json as default };",
+                        "value");
+        testTuples[2] = new TestTuple(
+                        "import { val } from '" + importName + "'; val;",
+                        "export { val } from './test2.js' " + keyword + " " + assertVal + ";",
+                        "value",
+                        "./test2.js",
+                        "export const val = 'value';", false);
+        testTuples[3] = new TestTuple(String.format("""
+                        (async function () {
+                            let {default:json} = await import('%s', { %s: %s } );
+                            console.log(json.val);
+                        });
+                        """, importName, keyword, assertVal),
+                        "let json = { val: 'value' }; export { json as default };",
+                        "value", true);
+        testTuples[4] = new TestTuple(String.format("""
+                        (async function () {
+                            let {default:json} = await import('%s', { %s: %s }, );
+                            console.log(json.val);
+                        });
+                        """, importName, keyword, assertVal),
+                        "let json = { val: 'value' }; export { json as default };",
+                        "value", true);
         return testTuples;
     }
 
@@ -188,14 +226,44 @@ public void testAssertMixedManyAttributesDanglingComma() throws IOException {
 
     @Test
     public void testNoLineTerminator() throws IOException {
-        TestTuple t = new TestTuple("var access = ''; Object.defineProperty(globalThis, 'assert', {get:function() { access = 'access'; }}); import { val } from './test.js' " + System.lineSeparator() +
-                        "assert" + System.lineSeparator() + " {}; access + ' ' + val;", "export const val = 'value';", "access value");
-        TestTuple t2 = new TestTuple("var access = ''; Object.defineProperty(globalThis, 'assert', {get:function() { access = 'access'; }}); import json from './test.js' " + System.lineSeparator() +
-                        "assert " + System.lineSeparator() + " {}; access + ' ' + json.val;", "let json = { val: 'value' }; export { json as default };", "access value");
-        TestTuple t3 = new TestTuple("import { val } from './test.js'; val;",
-                        "var access = ''; Object.defineProperty(globalThis, 'assert', {get:function() { access = 'access'; }}); export { val } from './test2.js' " + System.lineSeparator() +
-                                        " assert " + System.lineSeparator() + " {};",
-                        "value", "./test2.js", "export const val = 'value';", false);
+        // import assertions must be on the same line.
+        // import attributes may be on a separate line.
+        String expectedResult = "assert".equals(keyword) ? "assert,value" : "none,value";
+        TestTuple t = new TestTuple(String.format("""
+                        var access = 'none';
+                        Object.defineProperty(globalThis, '%1$s', {get:function() { access = '%1$s'; }});
+                        import { val } from './test.js'
+                        %1$s
+                         {};
+                        access + ',' + val;
+                        """, keyword),
+                        "export const val = 'value';",
+                        expectedResult);
+        TestTuple t2 = new TestTuple(String.format("""
+                        var access = 'none';
+                        Object.defineProperty(globalThis, '%1$s', {get:function() { access = '%1$s'; }});
+                        import json from './test.js'
+                        %1$s\s
+                         {};
+                        access + ',' + json.val;
+                        """, keyword), """
+                        let json = { val: 'value' };
+                        export { json as default };
+                        """,
+                        expectedResult);
+        TestTuple t3 = new TestTuple("""
+                        import { val, access } from './test.js';
+                        access + ',' + val;
+                        """, String.format("""
+                        export var access = 'none';
+                        Object.defineProperty(globalThis, '%1$s', {get:function() { access = '%1$s'; }});
+                        export { val } from './test2.js'\s
+                         %1$s\s
+                         {};
+                        """, keyword),
+                        expectedResult,
+                        "./test2.js",
+                        "export const val = 'value';", false);
         executeTest(t);
         executeTest(t2);
         executeTest(t3);

From dca183e81c5bb9f61d5c8d3f05f63022fb0d7d71 Mon Sep 17 00:00:00 2001
From: Andreas Woess 
Date: Thu, 8 Aug 2024 16:23:21 +0200
Subject: [PATCH 180/265] Preserve import attributes for indirect exports and
 clean up ExportNode and ImportNode.

---
 .../src/com/oracle/js/parser/Parser.java      |  4 +-
 .../js/parser/ParserContextModuleNode.java    |  4 +-
 .../com/oracle/js/parser/ir/ExportNode.java   | 33 ++++----
 .../js/parser/ir/ExportSpecifierNode.java     | 12 +--
 .../com/oracle/js/parser/ir/ImportNode.java   | 42 ++++++++--
 .../js/test/parser/ExportParserTest.java      | 82 ++++++++++++++++++-
 .../js/test/parser/ImportParserTest.java      | 60 +++++++++++++-
 7 files changed, 206 insertions(+), 31 deletions(-)

diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
index b5eb006a48f..0147b9fa72c 100644
--- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
+++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
@@ -7003,7 +7003,7 @@ private void importDeclaration(ParserContextModuleNode module) {
             Map attributes = withClause();
 
             module.addModuleRequest(ModuleRequest.create(moduleSpecifier, attributes));
-            module.addImport(new ImportNode(importToken, Token.descPosition(importToken), finish, specifier));
+            module.addImport(new ImportNode(importToken, Token.descPosition(importToken), finish, specifier, attributes));
         } else {
             // import ImportClause FromClause WithClause_opt;
             final List importEntries = new ArrayList<>();
@@ -7047,7 +7047,7 @@ private void importDeclaration(ParserContextModuleNode module) {
             FromNode fromNode = fromClause();
             Map attributes = withClause();
 
-            module.addImport(new ImportNode(importToken, Token.descPosition(importToken), finish, importClause, fromNode));
+            module.addImport(new ImportNode(importToken, Token.descPosition(importToken), finish, importClause, fromNode, attributes));
             TruffleString moduleSpecifier = fromNode.getModuleSpecifier().getValue();
             ModuleRequest moduleRequest = ModuleRequest.create(moduleSpecifier, attributes);
             module.addModuleRequest(moduleRequest);
diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ParserContextModuleNode.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ParserContextModuleNode.java
index 5e89639bec0..0eba2626188 100644
--- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ParserContextModuleNode.java
+++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ParserContextModuleNode.java
@@ -166,12 +166,12 @@ private void resolveExports() {
                             addIndirectExportEntry(exportToken, ExportEntry.exportIndirect(ee.getExportName(), ie.getModuleRequest(), ie.getImportName()));
                         }
                     } else {
-                        addIndirectExportEntry(exportToken, ee.withFrom(ModuleRequest.create(export.getFrom().getModuleSpecifier().getValue())));
+                        addIndirectExportEntry(exportToken, ee.withFrom(ModuleRequest.create(export.getFrom().getModuleSpecifier().getValue(), export.getAttributes())));
                     }
                 }
             } else if (export.getFrom() != null) {
                 TruffleString specifier = export.getFrom().getModuleSpecifier().getValue();
-                ModuleRequest moduleRequest = ModuleRequest.create(specifier, export.getAssertions());
+                ModuleRequest moduleRequest = ModuleRequest.create(specifier, export.getAttributes());
                 if (export.getExportIdentifier() == null) {
                     addStarExportEntry(ExportEntry.exportStarFrom(moduleRequest));
                 } else {
diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/ExportNode.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/ExportNode.java
index e1d32c1761c..146d9298ec8 100644
--- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/ExportNode.java
+++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/ExportNode.java
@@ -61,14 +61,14 @@ public class ExportNode extends Node {
 
     private final boolean isDefault;
 
-    private final Map assertions;
+    private final Map attributes;
 
-    public ExportNode(final long token, final int start, final int finish, final PropertyKey ident, final FromNode from, Map assertions) {
-        this(token, start, finish, null, from, ident, null, null, false, assertions);
+    public ExportNode(final long token, final int start, final int finish, final PropertyKey ident, final FromNode from, Map attributes) {
+        this(token, start, finish, null, from, ident, null, null, false, attributes);
     }
 
-    public ExportNode(final long token, final int start, final int finish, final NamedExportsNode exportClause, final FromNode from, Map assertions) {
-        this(token, start, finish, exportClause, from, null, null, null, false, assertions);
+    public ExportNode(final long token, final int start, final int finish, final NamedExportsNode exportClause, final FromNode from, Map attributes) {
+        this(token, start, finish, exportClause, from, null, null, null, false, attributes);
     }
 
     public ExportNode(final long token, final int start, final int finish, final PropertyKey ident, final Expression expression, final boolean isDefault) {
@@ -80,7 +80,7 @@ public ExportNode(final long token, final int start, final int finish, final Pro
     }
 
     private ExportNode(final long token, final int start, final int finish, final NamedExportsNode namedExports,
-                    final FromNode from, final PropertyKey exportIdent, final VarNode var, final Expression expression, final boolean isDefault, Map assertions) {
+                    final FromNode from, final PropertyKey exportIdent, final VarNode var, final Expression expression, final boolean isDefault, Map attributes) {
         super(token, start, finish);
         this.namedExports = namedExports;
         this.from = from;
@@ -88,14 +88,14 @@ private ExportNode(final long token, final int start, final int finish, final Na
         this.var = var;
         this.expression = expression;
         this.isDefault = isDefault;
-        this.assertions = Map.copyOf(assertions);
+        this.attributes = Map.copyOf(attributes);
         assert (namedExports == null) || (exportIdent == null);
         assert !isDefault || (namedExports == null && from == null);
         assert (var == null && expression == null) || isDefault || (exportIdent != null && exportIdent == getIdent(var, expression));
     }
 
     private ExportNode(final ExportNode node, final NamedExportsNode namedExports,
-                    final FromNode from, final PropertyKey exportIdent, final VarNode var, final Expression expression, Map assertions) {
+                    final FromNode from, final PropertyKey exportIdent, final VarNode var, final Expression expression, Map attributes) {
         super(node);
         this.isDefault = node.isDefault;
 
@@ -104,7 +104,7 @@ private ExportNode(final ExportNode node, final NamedExportsNode namedExports,
         this.exportIdent = exportIdent;
         this.var = var;
         this.expression = expression;
-        this.assertions = Map.copyOf(assertions);
+        this.attributes = Map.copyOf(attributes);
     }
 
     public NamedExportsNode getNamedExports() {
@@ -131,8 +131,8 @@ public boolean isDefault() {
         return isDefault;
     }
 
-    public Map getAssertions() {
-        return assertions;
+    public Map getAttributes() {
+        return attributes;
     }
 
     public ExportNode setExportClause(NamedExportsNode exportClause) {
@@ -140,7 +140,7 @@ public ExportNode setExportClause(NamedExportsNode exportClause) {
         if (this.namedExports == exportClause) {
             return this;
         }
-        return new ExportNode(this, exportClause, from, exportIdent, var, expression, assertions);
+        return new ExportNode(this, exportClause, from, exportIdent, var, expression, attributes);
     }
 
     public ExportNode setFrom(FromNode from) {
@@ -148,7 +148,7 @@ public ExportNode setFrom(FromNode from) {
         if (this.from == from) {
             return this;
         }
-        return new ExportNode(this, namedExports, from, exportIdent, var, expression, assertions);
+        return new ExportNode(this, namedExports, from, exportIdent, var, expression, attributes);
     }
 
     @Override
@@ -161,7 +161,7 @@ public Node accept(NodeVisitor visitor) {
             PropertyKey newIdent = (exportIdent == null || isDefault()) ? exportIdent : getIdent(newVar, newExpression);
             ExportNode newNode = (this.namedExports == newExportClause && this.from == newFrom && this.exportIdent == newIdent && this.var == newVar && this.expression == newExpression)
                             ? this
-                            : new ExportNode(this, namedExports, from, exportIdent, var, expression, assertions);
+                            : new ExportNode(this, namedExports, from, exportIdent, var, expression, attributes);
             return visitor.leaveExportNode(newNode);
         }
 
@@ -209,6 +209,11 @@ public void toString(StringBuilder sb, boolean printType) {
             }
             if (from != null) {
                 from.toString(sb, printType);
+
+                if (!attributes.isEmpty()) {
+                    sb.append(" with ");
+                    ImportNode.attributesToString(attributes, sb);
+                }
             }
             sb.append(';');
         }
diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/ExportSpecifierNode.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/ExportSpecifierNode.java
index f40545592ff..5e5aac28fc0 100644
--- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/ExportSpecifierNode.java
+++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/ExportSpecifierNode.java
@@ -41,6 +41,8 @@
 
 package com.oracle.js.parser.ir;
 
+import java.util.Objects;
+
 import com.oracle.js.parser.ir.visitor.NodeVisitor;
 import com.oracle.js.parser.ir.visitor.TranslatorNodeVisitor;
 
@@ -52,13 +54,13 @@ public class ExportSpecifierNode extends Node {
 
     public ExportSpecifierNode(final long token, final int start, final int finish, final PropertyKey identifier, final PropertyKey exportIdentifier) {
         super(token, start, finish);
-        this.identifier = identifier;
+        this.identifier = Objects.requireNonNull(identifier);
         this.exportIdentifier = exportIdentifier;
     }
 
     private ExportSpecifierNode(final ExportSpecifierNode node, final PropertyKey identifier, final PropertyKey exportIdentifier) {
         super(node);
-        this.identifier = identifier;
+        this.identifier = Objects.requireNonNull(identifier);
         this.exportIdentifier = exportIdentifier;
     }
 
@@ -103,11 +105,11 @@ public  R accept(TranslatorNodeVisitor visitor)
 
     @Override
     public void toString(StringBuilder sb, boolean printType) {
-        if (identifier != null) {
-            ((Node) identifier).toString(sb, printType);
+        ((Node) identifier).toString(sb, printType);
+        if (exportIdentifier != null) {
             sb.append(" as ");
+            ((Node) exportIdentifier).toString(sb, printType);
         }
-        ((Node) exportIdentifier).toString(sb, printType);
     }
 
 }
diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/ImportNode.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/ImportNode.java
index f826dbc4747..70ed4ded9af 100644
--- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/ImportNode.java
+++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/ImportNode.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * The Universal Permissive License (UPL), Version 1.0
@@ -41,6 +41,8 @@
 
 package com.oracle.js.parser.ir;
 
+import java.util.Map;
+
 import com.oracle.js.parser.ir.visitor.NodeVisitor;
 import com.oracle.js.parser.ir.visitor.TranslatorNodeVisitor;
 import com.oracle.truffle.api.strings.TruffleString;
@@ -53,19 +55,25 @@ public class ImportNode extends Node {
 
     private final FromNode from;
 
-    public ImportNode(final long token, final int start, final int finish, final LiteralNode moduleSpecifier) {
-        this(token, start, finish, moduleSpecifier, null, null);
+    private final Map attributes;
+
+    public ImportNode(long token, int start, int finish, LiteralNode moduleSpecifier,
+                    Map attributes) {
+        this(token, start, finish, moduleSpecifier, null, null, attributes);
     }
 
-    public ImportNode(final long token, final int start, final int finish, final ImportClauseNode importClause, final FromNode from) {
-        this(token, start, finish, null, importClause, from);
+    public ImportNode(long token, int start, int finish, ImportClauseNode importClause, final FromNode from,
+                    Map attributes) {
+        this(token, start, finish, null, importClause, from, attributes);
     }
 
-    private ImportNode(final long token, final int start, final int finish, final LiteralNode moduleSpecifier, ImportClauseNode importClause, FromNode from) {
+    private ImportNode(long token, int start, int finish, LiteralNode moduleSpecifier, ImportClauseNode importClause, FromNode from,
+                    Map attributes) {
         super(token, start, finish);
         this.moduleSpecifier = moduleSpecifier;
         this.importClause = importClause;
         this.from = from;
+        this.attributes = attributes;
     }
 
     private ImportNode(final ImportNode node, final LiteralNode moduleSpecifier, ImportClauseNode importClause, FromNode from) {
@@ -73,6 +81,7 @@ private ImportNode(final ImportNode node, final LiteralNode modul
         this.moduleSpecifier = moduleSpecifier;
         this.importClause = importClause;
         this.from = from;
+        this.attributes = node.attributes;
     }
 
     public LiteralNode getModuleSpecifier() {
@@ -87,6 +96,10 @@ public FromNode getFrom() {
         return from;
     }
 
+    public Map getAttributes() {
+        return attributes;
+    }
+
     public ImportNode setModuleSpecifier(LiteralNode moduleSpecifier) {
         if (this.moduleSpecifier == moduleSpecifier) {
             return this;
@@ -137,7 +150,24 @@ public void toString(StringBuilder sb, boolean printType) {
             sb.append(' ');
             from.toString(sb, printType);
         }
+        if (!attributes.isEmpty()) {
+            sb.append(" with ");
+            attributesToString(attributes, sb);
+        }
         sb.append(';');
     }
 
+    static void attributesToString(Map attributes, StringBuilder sb) {
+        sb.append("{");
+        for (var iterator = attributes.entrySet().iterator(); iterator.hasNext();) {
+            var attr = iterator.next();
+            sb.append(attr.getKey());
+            sb.append(": ");
+            sb.append('"').append(attr.getValue()).append('"');
+            if (iterator.hasNext()) {
+                sb.append(", ");
+            }
+        }
+        sb.append("}");
+    }
 }
diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ExportParserTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ExportParserTest.java
index 261c0e1163f..fd2df17bb54 100644
--- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ExportParserTest.java
+++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ExportParserTest.java
@@ -43,9 +43,11 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import java.util.List;
+import java.util.Map;
 
 import org.junit.Test;
 
@@ -64,13 +66,17 @@
 import com.oracle.js.parser.ir.FunctionNode;
 import com.oracle.js.parser.ir.IdentNode;
 import com.oracle.js.parser.ir.LiteralNode;
+import com.oracle.js.parser.ir.Module;
+import com.oracle.js.parser.ir.Module.ExportEntry;
 import com.oracle.js.parser.ir.ObjectNode;
 import com.oracle.js.parser.ir.VarNode;
+import com.oracle.truffle.api.strings.TruffleString;
+import com.oracle.truffle.js.runtime.Strings;
 
 public class ExportParserTest {
 
     private static FunctionNode parseModule(String code) {
-        ScriptEnvironment env = ScriptEnvironment.builder().strict(true).build();
+        ScriptEnvironment env = ScriptEnvironment.builder().strict(true).ecmaScriptVersion(ScriptEnvironment.ES_2020).importAttributes(true).build();
         Parser parser = new Parser(env, Source.sourceFor("name", code), new ErrorManager.ThrowErrorManager());
         return parser.parseModule("moduleName");
     }
@@ -251,6 +257,80 @@ public void testFromSpecifiers() {
         assertEquals(ImportParserTest.BAR, specifier.getIdentifier().getPropertyNameTS());
     }
 
+    @Test
+    public void testExportNamedFromWithAttributes() {
+        String code = """
+                        export {bar} from "foo" with {type: "json"};
+                        """;
+        Module module = parseModule(code).getModule();
+        Map expectedAttributes = Map.of(Strings.fromJavaString("type"), Strings.fromJavaString("json"));
+
+        List exports = module.getExports();
+        assertEquals(1, exports.size());
+        ExportNode export = exports.get(0);
+        assertFalse(export.isDefault());
+        assertEquals(ImportParserTest.FOO, export.getFrom().getModuleSpecifier().getValue());
+        List specifiers = export.getNamedExports().getExportSpecifiers();
+        assertEquals(1, specifiers.size());
+        assertEquals(ImportParserTest.BAR, specifiers.get(0).getIdentifier().getPropertyNameTS());
+
+        assertEquals(export.toString(), expectedAttributes.size(), export.getAttributes().size());
+        assertEquals(export.toString(), expectedAttributes, export.getAttributes());
+
+        assertEquals(1, module.getIndirectExportEntries().size());
+        ExportEntry exportEntry = module.getIndirectExportEntries().get(0);
+        assertEquals(exportEntry.toString(), expectedAttributes.size(), exportEntry.getModuleRequest().getAttributes().size());
+        assertEquals(exportEntry.toString(), expectedAttributes, exportEntry.getModuleRequest().getAttributes());
+    }
+
+    @Test
+    public void testExportStarFromWithAttributes() {
+        String code = """
+                        export * from "foo" with {type: "json"};
+                        """;
+        Module module = parseModule(code).getModule();
+        Map expectedAttributes = Map.of(Strings.fromJavaString("type"), Strings.fromJavaString("json"));
+
+        List exports = module.getExports();
+        assertEquals(1, exports.size());
+        ExportNode export = exports.get(0);
+        assertFalse(export.isDefault());
+        assertEquals(ImportParserTest.FOO, export.getFrom().getModuleSpecifier().getValue());
+
+        assertEquals(export.toString(), expectedAttributes.size(), export.getAttributes().size());
+        assertEquals(export.toString(), expectedAttributes, export.getAttributes());
+
+        assertEquals(1, module.getStarExportEntries().size());
+        ExportEntry exportEntry = module.getStarExportEntries().get(0);
+        assertEquals(exportEntry.toString(), expectedAttributes.size(), exportEntry.getModuleRequest().getAttributes().size());
+        assertEquals(exportEntry.toString(), expectedAttributes, exportEntry.getModuleRequest().getAttributes());
+    }
+
+    @Test
+    public void testExportNamespaceFromWithAttributes() {
+        String code = """
+                        export * as bar from "foo" with {type: "json"};
+                        """;
+        Module module = parseModule(code).getModule();
+        Map expectedAttributes = Map.of(Strings.fromJavaString("type"), Strings.fromJavaString("json"));
+
+        List exports = module.getExports();
+        assertEquals(1, exports.size());
+        ExportNode export = exports.get(0);
+        assertFalse(export.isDefault());
+        assertEquals(ImportParserTest.FOO, export.getFrom().getModuleSpecifier().getValue());
+        assertNull(export.toString(), export.getNamedExports());
+        assertEquals(export.toString(), ImportParserTest.BAR, export.getExportIdentifier().getPropertyNameTS());
+
+        assertEquals(export.toString(), expectedAttributes.size(), export.getAttributes().size());
+        assertEquals(export.toString(), expectedAttributes, export.getAttributes());
+
+        assertEquals(1, module.getIndirectExportEntries().size());
+        ExportEntry exportEntry = module.getIndirectExportEntries().get(0);
+        assertEquals(exportEntry.toString(), expectedAttributes.size(), exportEntry.getModuleRequest().getAttributes().size());
+        assertEquals(exportEntry.toString(), expectedAttributes, exportEntry.getModuleRequest().getAttributes());
+    }
+
     @Test
     public void testFunction() {
         Expression expression = testHelper("export function foo () {}", false);
diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ImportParserTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ImportParserTest.java
index 600f0f67788..3a6ada731d1 100644
--- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ImportParserTest.java
+++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ImportParserTest.java
@@ -43,6 +43,7 @@
 import static org.junit.Assert.assertEquals;
 
 import java.util.List;
+import java.util.Map;
 
 import org.junit.Test;
 
@@ -56,6 +57,8 @@
 import com.oracle.js.parser.ir.ImportClauseNode;
 import com.oracle.js.parser.ir.ImportNode;
 import com.oracle.js.parser.ir.ImportSpecifierNode;
+import com.oracle.js.parser.ir.Module;
+import com.oracle.js.parser.ir.Module.ImportEntry;
 import com.oracle.js.parser.ir.NameSpaceImportNode;
 import com.oracle.truffle.api.strings.TruffleString;
 import com.oracle.truffle.js.runtime.Strings;
@@ -69,7 +72,7 @@ public class ImportParserTest {
     public static final TruffleString DEFAULT = Strings.constant("default");
 
     private static FunctionNode parseModule(String code) {
-        ScriptEnvironment env = ScriptEnvironment.builder().strict(true).build();
+        ScriptEnvironment env = ScriptEnvironment.builder().strict(true).ecmaScriptVersion(ScriptEnvironment.ES_2020).importAttributes(true).build();
         Parser parser = new Parser(env, Source.sourceFor("name", code), new ErrorManager.ThrowErrorManager());
         return parser.parseModule("moduleName");
     }
@@ -240,4 +243,59 @@ public void testNamespaceSpecifier() {
         assertEquals(FOO, from.getModuleSpecifier().getValue());
     }
 
+    @Test
+    public void testImportNamedWithAttributes() {
+        String code = """
+                        import {bar} from "foo" with {type: "json"};
+                        """;
+        Module module = parseModule(code).getModule();
+        Map expectedAttributes = Map.of(Strings.fromJavaString("type"), Strings.fromJavaString("json"));
+
+        List imports = module.getImports();
+        assertEquals(1, imports.size());
+        ImportNode importNode = imports.get(0);
+
+        FromNode from = importNode.getFrom();
+        assertEquals(FOO, from.getModuleSpecifier().getValue());
+        ImportClauseNode clause = importNode.getImportClause();
+        List specifiers = clause.getNamedImports().getImportSpecifiers();
+        assertEquals(1, specifiers.size());
+        ImportSpecifierNode specifier = specifiers.get(0);
+        assertEquals(BAR, specifier.getBindingIdentifier().getNameTS());
+
+        assertEquals(importNode.toString(), expectedAttributes.size(), importNode.getAttributes().size());
+        assertEquals(importNode.toString(), expectedAttributes, importNode.getAttributes());
+
+        assertEquals(1, module.getImportEntries().size());
+        ImportEntry importEntry = module.getImportEntries().get(0);
+        assertEquals(importEntry.toString(), expectedAttributes.size(), importEntry.getModuleRequest().getAttributes().size());
+        assertEquals(importEntry.toString(), expectedAttributes, importEntry.getModuleRequest().getAttributes());
+    }
+
+    @Test
+    public void testImportNamespaceWithAttributes() {
+        String code = """
+                        import * as bar from "foo" with {type: "json"};
+                        """;
+        Module module = parseModule(code).getModule();
+        Map expectedAttributes = Map.of(Strings.fromJavaString("type"), Strings.fromJavaString("json"));
+
+        List imports = module.getImports();
+        assertEquals(1, imports.size());
+        ImportNode importNode = imports.get(0);
+
+        FromNode from = importNode.getFrom();
+        assertEquals(FOO, from.getModuleSpecifier().getValue());
+        ImportClauseNode clause = importNode.getImportClause();
+        NameSpaceImportNode nameSpaceImport = clause.getNameSpaceImport();
+        assertEquals(BAR, nameSpaceImport.getBindingIdentifier().getNameTS());
+
+        assertEquals(importNode.toString(), expectedAttributes.size(), importNode.getAttributes().size());
+        assertEquals(importNode.toString(), expectedAttributes, importNode.getAttributes());
+
+        assertEquals(1, module.getImportEntries().size());
+        ImportEntry importEntry = module.getImportEntries().get(0);
+        assertEquals(importEntry.toString(), expectedAttributes.size(), importEntry.getModuleRequest().getAttributes().size());
+        assertEquals(importEntry.toString(), expectedAttributes, importEntry.getModuleRequest().getAttributes());
+    }
 }

From 37ef42a480465116fd38a72b9771e97223e7ca0f Mon Sep 17 00:00:00 2001
From: Andreas Woess 
Date: Thu, 8 Aug 2024 20:02:58 +0200
Subject: [PATCH 181/265] Remove FromClause parse node.

---
 .../src/com/oracle/js/parser/Parser.java      | 31 +++---
 .../js/parser/ParserContextModuleNode.java    |  8 +-
 .../com/oracle/js/parser/ir/ExportNode.java   | 57 ++++++-----
 .../src/com/oracle/js/parser/ir/FromNode.java | 95 -------------------
 .../com/oracle/js/parser/ir/ImportNode.java   | 52 ++++------
 .../js/parser/ir/visitor/NodeVisitor.java     | 15 +--
 .../ir/visitor/TranslatorNodeVisitor.java     |  9 +-
 .../js/test/parser/ExportParserTest.java      | 19 ++--
 .../js/test/parser/ImportParserTest.java      | 37 +++-----
 9 files changed, 92 insertions(+), 231 deletions(-)
 delete mode 100644 graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/FromNode.java

diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
index 0147b9fa72c..af0eca7781e 100644
--- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
+++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java
@@ -147,7 +147,6 @@
 import com.oracle.js.parser.ir.ExpressionList;
 import com.oracle.js.parser.ir.ExpressionStatement;
 import com.oracle.js.parser.ir.ForNode;
-import com.oracle.js.parser.ir.FromNode;
 import com.oracle.js.parser.ir.FunctionNode;
 import com.oracle.js.parser.ir.IdentNode;
 import com.oracle.js.parser.ir.IfNode;
@@ -7044,11 +7043,11 @@ private void importDeclaration(ParserContextModuleNode module) {
                 throw error(AbstractParser.message(MSG_EXPECTED_IMPORT));
             }
 
-            FromNode fromNode = fromClause();
+            LiteralNode specifier = fromClause();
             Map attributes = withClause();
 
-            module.addImport(new ImportNode(importToken, Token.descPosition(importToken), finish, importClause, fromNode, attributes));
-            TruffleString moduleSpecifier = fromNode.getModuleSpecifier().getValue();
+            module.addImport(new ImportNode(importToken, Token.descPosition(importToken), finish, importClause, specifier, attributes));
+            TruffleString moduleSpecifier = specifier.getValue();
             ModuleRequest moduleRequest = ModuleRequest.create(moduleSpecifier, attributes);
             module.addModuleRequest(moduleRequest);
             for (int i = 0; i < importEntries.size(); i++) {
@@ -7201,9 +7200,7 @@ private NamedImportsNode namedImports(List importEntries) {
      *      from ModuleSpecifier
      * 
*/ - private FromNode fromClause() { - int fromStart = start; - long fromToken = token; + private LiteralNode fromClause() { expect(FROM); if (type == STRING || type == ESCSTRING) { @@ -7211,7 +7208,7 @@ private FromNode fromClause() { long specifierToken = token; next(); LiteralNode specifier = LiteralNode.newInstance(specifierToken, moduleSpecifier); - return new FromNode(fromToken, fromStart, finish, specifier); + return specifier; } else { throw error(expectMessage(STRING)); } @@ -7245,25 +7242,25 @@ private void exportDeclaration(ParserContextModuleNode module) { next(); exportName = moduleExportName(); } - FromNode from = fromClause(); + LiteralNode fromSpecifier = fromClause(); Map attributes = withClause(); - TruffleString moduleRequest = from.getModuleSpecifier().getValue(); - module.addModuleRequest(ModuleRequest.create(moduleRequest, attributes)); - module.addExport(new ExportNode(exportToken, Token.descPosition(exportToken), finish, exportName, from, attributes)); + TruffleString moduleSpecifier = fromSpecifier.getValue(); + module.addModuleRequest(ModuleRequest.create(moduleSpecifier, attributes)); + module.addExport(new ExportNode(exportToken, Token.descPosition(exportToken), finish, exportName, fromSpecifier, attributes)); endOfLine(); break; } case LBRACE: { NamedExportsNode exportClause = namedExports(); - FromNode from = null; + LiteralNode fromSpecifier = null; Map attributes = Map.of(); if (type == FROM) { - from = fromClause(); + fromSpecifier = fromClause(); attributes = withClause(); - TruffleString moduleRequest = from.getModuleSpecifier().getValue(); - module.addModuleRequest(ModuleRequest.create(moduleRequest, attributes)); + TruffleString moduleSpecifier = fromSpecifier.getValue(); + module.addModuleRequest(ModuleRequest.create(moduleSpecifier, attributes)); } else { for (ExportSpecifierNode export : exportClause.getExportSpecifiers()) { if (!(export.getIdentifier() instanceof IdentNode)) { @@ -7271,7 +7268,7 @@ private void exportDeclaration(ParserContextModuleNode module) { } } } - module.addExport(new ExportNode(exportToken, Token.descPosition(exportToken), finish, exportClause, from, attributes)); + module.addExport(new ExportNode(exportToken, Token.descPosition(exportToken), finish, exportClause, fromSpecifier, attributes)); endOfLine(); break; } diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ParserContextModuleNode.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ParserContextModuleNode.java index 0eba2626188..1b983624887 100644 --- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ParserContextModuleNode.java +++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ParserContextModuleNode.java @@ -154,7 +154,7 @@ private void resolveExports() { } else { ee = ExportEntry.exportSpecifier(localName); } - if (export.getFrom() == null) { + if (export.getModuleSpecifier() == null) { ImportEntry ie = importedLocalNames.get(localName.toJavaStringUncached()); if (ie == null) { addLocalExportEntry(exportToken, ee); @@ -166,11 +166,11 @@ private void resolveExports() { addIndirectExportEntry(exportToken, ExportEntry.exportIndirect(ee.getExportName(), ie.getModuleRequest(), ie.getImportName())); } } else { - addIndirectExportEntry(exportToken, ee.withFrom(ModuleRequest.create(export.getFrom().getModuleSpecifier().getValue(), export.getAttributes()))); + addIndirectExportEntry(exportToken, ee.withFrom(ModuleRequest.create(export.getModuleSpecifier().getValue(), export.getAttributes()))); } } - } else if (export.getFrom() != null) { - TruffleString specifier = export.getFrom().getModuleSpecifier().getValue(); + } else if (export.getModuleSpecifier() != null) { + TruffleString specifier = export.getModuleSpecifier().getValue(); ModuleRequest moduleRequest = ModuleRequest.create(specifier, export.getAttributes()); if (export.getExportIdentifier() == null) { addStarExportEntry(ExportEntry.exportStarFrom(moduleRequest)); diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/ExportNode.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/ExportNode.java index 146d9298ec8..2407b749666 100644 --- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/ExportNode.java +++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/ExportNode.java @@ -51,7 +51,7 @@ public class ExportNode extends Node { private final NamedExportsNode namedExports; - private final FromNode from; + private final LiteralNode moduleSpecifier; private final PropertyKey exportIdent; @@ -63,44 +63,47 @@ public class ExportNode extends Node { private final Map attributes; - public ExportNode(final long token, final int start, final int finish, final PropertyKey ident, final FromNode from, Map attributes) { - this(token, start, finish, null, from, ident, null, null, false, attributes); + public ExportNode(long token, int start, int finish, PropertyKey ident, + LiteralNode moduleSpecifier, Map attributes) { + this(token, start, finish, null, moduleSpecifier, ident, null, null, false, attributes); } - public ExportNode(final long token, final int start, final int finish, final NamedExportsNode exportClause, final FromNode from, Map attributes) { - this(token, start, finish, exportClause, from, null, null, null, false, attributes); + public ExportNode(long token, int start, int finish, NamedExportsNode exportClause, + LiteralNode moduleSpecifier, Map attributes) { + this(token, start, finish, exportClause, moduleSpecifier, null, null, null, false, attributes); } - public ExportNode(final long token, final int start, final int finish, final PropertyKey ident, final Expression expression, final boolean isDefault) { + public ExportNode(long token, int start, int finish, PropertyKey ident, Expression expression, boolean isDefault) { this(token, start, finish, null, null, ident, null, expression, isDefault, Map.of()); } - public ExportNode(final long token, final int start, final int finish, final PropertyKey ident, final VarNode var) { + public ExportNode(long token, int start, int finish, PropertyKey ident, VarNode var) { this(token, start, finish, null, null, ident, var, null, false, Map.of()); } - private ExportNode(final long token, final int start, final int finish, final NamedExportsNode namedExports, - final FromNode from, final PropertyKey exportIdent, final VarNode var, final Expression expression, final boolean isDefault, Map attributes) { + private ExportNode(long token, int start, int finish, NamedExportsNode namedExports, + LiteralNode moduleSpecifier, PropertyKey exportIdent, VarNode var, Expression expression, boolean isDefault, + Map attributes) { super(token, start, finish); this.namedExports = namedExports; - this.from = from; + this.moduleSpecifier = moduleSpecifier; this.exportIdent = exportIdent; this.var = var; this.expression = expression; this.isDefault = isDefault; this.attributes = Map.copyOf(attributes); assert (namedExports == null) || (exportIdent == null); - assert !isDefault || (namedExports == null && from == null); + assert !isDefault || (namedExports == null && moduleSpecifier == null); assert (var == null && expression == null) || isDefault || (exportIdent != null && exportIdent == getIdent(var, expression)); } - private ExportNode(final ExportNode node, final NamedExportsNode namedExports, - final FromNode from, final PropertyKey exportIdent, final VarNode var, final Expression expression, Map attributes) { + private ExportNode(ExportNode node, NamedExportsNode namedExports, + LiteralNode moduleSpecifier, PropertyKey exportIdent, VarNode var, Expression expression, Map attributes) { super(node); this.isDefault = node.isDefault; this.namedExports = namedExports; - this.from = from; + this.moduleSpecifier = moduleSpecifier; this.exportIdent = exportIdent; this.var = var; this.expression = expression; @@ -111,8 +114,8 @@ public NamedExportsNode getNamedExports() { return namedExports; } - public FromNode getFrom() { - return from; + public LiteralNode getModuleSpecifier() { + return moduleSpecifier; } public PropertyKey getExportIdentifier() { @@ -140,28 +143,29 @@ public ExportNode setExportClause(NamedExportsNode exportClause) { if (this.namedExports == exportClause) { return this; } - return new ExportNode(this, exportClause, from, exportIdent, var, expression, attributes); + return new ExportNode(this, exportClause, moduleSpecifier, exportIdent, var, expression, attributes); } - public ExportNode setFrom(FromNode from) { + public ExportNode setFromSpecifier(LiteralNode from) { assert exportIdent == null; - if (this.from == from) { + if (this.moduleSpecifier == from) { return this; } return new ExportNode(this, namedExports, from, exportIdent, var, expression, attributes); } + @SuppressWarnings("unchecked") @Override public Node accept(NodeVisitor visitor) { if (visitor.enterExportNode(this)) { NamedExportsNode newExportClause = namedExports == null ? null : (NamedExportsNode) namedExports.accept(visitor); - FromNode newFrom = from == null ? null : (FromNode) from.accept(visitor); + LiteralNode newFrom = moduleSpecifier == null ? null : (LiteralNode) moduleSpecifier.accept(visitor); VarNode newVar = var == null ? null : (VarNode) var.accept(visitor); Expression newExpression = expression == null ? null : (Expression) expression.accept(visitor); PropertyKey newIdent = (exportIdent == null || isDefault()) ? exportIdent : getIdent(newVar, newExpression); - ExportNode newNode = (this.namedExports == newExportClause && this.from == newFrom && this.exportIdent == newIdent && this.var == newVar && this.expression == newExpression) + ExportNode newNode = (this.namedExports == newExportClause && this.moduleSpecifier == newFrom && this.exportIdent == newIdent && this.var == newVar && this.expression == newExpression) ? this - : new ExportNode(this, namedExports, from, exportIdent, var, expression, attributes); + : new ExportNode(this, namedExports, moduleSpecifier, exportIdent, var, expression, attributes); return visitor.leaveExportNode(newNode); } @@ -202,13 +206,16 @@ public void toString(StringBuilder sb, boolean printType) { if (namedExports == null) { sb.append("* "); if (exportIdent != null) { - sb.append("as ").append(exportIdent).append(' '); + sb.append("as ").append(exportIdent); } } else { namedExports.toString(sb, printType); } - if (from != null) { - from.toString(sb, printType); + if (moduleSpecifier != null) { + sb.append(' '); + sb.append("from"); + sb.append(' '); + moduleSpecifier.toString(sb, printType); if (!attributes.isEmpty()) { sb.append(" with "); diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/FromNode.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/FromNode.java deleted file mode 100644 index 65332db63b8..00000000000 --- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/FromNode.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * The Universal Permissive License (UPL), Version 1.0 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or - * data (collectively the "Software"), free of charge and under any and all - * copyright rights in the Software, and any and all patent rights owned or - * freely licensable by each licensor hereunder covering either (i) the - * unmodified Software as contributed to or provided by such licensor, or (ii) - * the Larger Works (as defined below), to deal in both - * - * (a) the Software, and - * - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * - * The above copyright notice and either this complete permission notice or at a - * minimum a reference to the UPL must be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package com.oracle.js.parser.ir; - -import com.oracle.js.parser.ir.visitor.NodeVisitor; -import com.oracle.js.parser.ir.visitor.TranslatorNodeVisitor; -import com.oracle.truffle.api.strings.TruffleString; - -public class FromNode extends Node { - - private final LiteralNode moduleSpecifier; - - public FromNode(final long token, final int start, final int finish, final LiteralNode moduleSpecifier) { - super(token, start, finish); - this.moduleSpecifier = moduleSpecifier; - } - - private FromNode(final FromNode node, final LiteralNode moduleSpecifier) { - super(node); - this.moduleSpecifier = moduleSpecifier; - } - - public LiteralNode getModuleSpecifier() { - return moduleSpecifier; - } - - public FromNode setModuleSpecifier(LiteralNode moduleSpecifier) { - if (this.moduleSpecifier == moduleSpecifier) { - return this; - } - return new FromNode(this, moduleSpecifier); - } - - @Override - @SuppressWarnings("unchecked") - public Node accept(NodeVisitor visitor) { - if (visitor.enterFromNode(this)) { - return visitor.leaveFromNode(setModuleSpecifier((LiteralNode) moduleSpecifier.accept(visitor))); - } - - return this; - } - - @Override - public R accept(TranslatorNodeVisitor visitor) { - return visitor.enterFromNode(this); - } - - @Override - public void toString(StringBuilder sb, boolean printType) { - sb.append("from"); - sb.append(' '); - moduleSpecifier.toString(sb, printType); - } - -} diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/ImportNode.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/ImportNode.java index 70ed4ded9af..74e6e79dc28 100644 --- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/ImportNode.java +++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/ImportNode.java @@ -42,6 +42,7 @@ package com.oracle.js.parser.ir; import java.util.Map; +import java.util.Objects; import com.oracle.js.parser.ir.visitor.NodeVisitor; import com.oracle.js.parser.ir.visitor.TranslatorNodeVisitor; @@ -53,35 +54,30 @@ public class ImportNode extends Node { private final ImportClauseNode importClause; - private final FromNode from; - private final Map attributes; public ImportNode(long token, int start, int finish, LiteralNode moduleSpecifier, Map attributes) { - this(token, start, finish, moduleSpecifier, null, null, attributes); + this(token, start, finish, moduleSpecifier, null, attributes); } - public ImportNode(long token, int start, int finish, ImportClauseNode importClause, final FromNode from, + public ImportNode(long token, int start, int finish, ImportClauseNode importClause, LiteralNode moduleSpecifier, Map attributes) { - this(token, start, finish, null, importClause, from, attributes); + this(token, start, finish, moduleSpecifier, importClause, attributes); } - private ImportNode(long token, int start, int finish, LiteralNode moduleSpecifier, ImportClauseNode importClause, FromNode from, - Map attributes) { + private ImportNode(long token, int start, int finish, LiteralNode moduleSpecifier, ImportClauseNode importClause, Map attributes) { super(token, start, finish); - this.moduleSpecifier = moduleSpecifier; + this.moduleSpecifier = Objects.requireNonNull(moduleSpecifier); this.importClause = importClause; - this.from = from; - this.attributes = attributes; + this.attributes = Objects.requireNonNull(attributes); } - private ImportNode(final ImportNode node, final LiteralNode moduleSpecifier, ImportClauseNode importClause, FromNode from) { + private ImportNode(final ImportNode node, final LiteralNode moduleSpecifier, ImportClauseNode importClause) { super(node); - this.moduleSpecifier = moduleSpecifier; + this.moduleSpecifier = Objects.requireNonNull(moduleSpecifier); this.importClause = importClause; - this.from = from; - this.attributes = node.attributes; + this.attributes = Objects.requireNonNull(node.attributes); } public LiteralNode getModuleSpecifier() { @@ -92,10 +88,6 @@ public ImportClauseNode getImportClause() { return importClause; } - public FromNode getFrom() { - return from; - } - public Map getAttributes() { return attributes; } @@ -104,31 +96,23 @@ public ImportNode setModuleSpecifier(LiteralNode moduleSpecifier) if (this.moduleSpecifier == moduleSpecifier) { return this; } - return new ImportNode(this, moduleSpecifier, importClause, from); + return new ImportNode(this, moduleSpecifier, importClause); } public ImportNode setImportClause(ImportClauseNode importClause) { if (this.importClause == importClause) { return this; } - return new ImportNode(this, moduleSpecifier, importClause, from); - } - - public ImportNode setFrom(FromNode from) { - if (this.from == from) { - return this; - } - return new ImportNode(this, moduleSpecifier, importClause, from); + return new ImportNode(this, moduleSpecifier, importClause); } @Override @SuppressWarnings("unchecked") public Node accept(NodeVisitor visitor) { if (visitor.enterImportNode(this)) { - LiteralNode newModuleSpecifier = moduleSpecifier == null ? null : (LiteralNode) moduleSpecifier.accept(visitor); + LiteralNode newModuleSpecifier = (LiteralNode) moduleSpecifier.accept(visitor); ImportClauseNode newImportClause = importClause == null ? null : (ImportClauseNode) importClause.accept(visitor); - FromNode newFrom = from == null ? null : (FromNode) from.accept(visitor); - return visitor.leaveImportNode(setModuleSpecifier(newModuleSpecifier).setImportClause(newImportClause).setFrom(newFrom)); + return visitor.leaveImportNode(setModuleSpecifier(newModuleSpecifier).setImportClause(newImportClause)); } return this; @@ -143,13 +127,13 @@ public R accept(TranslatorNodeVisitor visitor) public void toString(StringBuilder sb, boolean printType) { sb.append("import"); sb.append(' '); - if (moduleSpecifier != null) { - moduleSpecifier.toString(sb, printType); - } else { + if (importClause != null) { importClause.toString(sb, printType); sb.append(' '); - from.toString(sb, printType); + sb.append("from"); + sb.append(' '); } + moduleSpecifier.toString(sb, printType); if (!attributes.isEmpty()) { sb.append(" with "); attributesToString(attributes, sb); diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/visitor/NodeVisitor.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/visitor/NodeVisitor.java index f1ccb288e15..243352eabd2 100644 --- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/visitor/NodeVisitor.java +++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/visitor/NodeVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -60,7 +60,6 @@ import com.oracle.js.parser.ir.ExportSpecifierNode; import com.oracle.js.parser.ir.ExpressionStatement; import com.oracle.js.parser.ir.ForNode; -import com.oracle.js.parser.ir.FromNode; import com.oracle.js.parser.ir.FunctionNode; import com.oracle.js.parser.ir.IdentNode; import com.oracle.js.parser.ir.IfNode; @@ -467,14 +466,6 @@ public Node leaveForNode(final ForNode forNode) { return leaveDefault(forNode); } - public boolean enterFromNode(final FromNode fromNode) { - return enterDefault(fromNode); - } - - public Node leaveFromNode(final FromNode fromNode) { - return leaveDefault(fromNode); - } - /** * Callback for entering a FunctionNode * @@ -957,7 +948,7 @@ public Node leaveTemplateLiteralNode(final TemplateLiteralNode templateLiteralNo /** * Callback for entering a ClassElement - * + * * @param element the node * @return true if traversal should continue and node children be traversed, false otherwise */ @@ -967,7 +958,7 @@ public boolean enterClassElement(final ClassElement element) { /** * Callback for leaving a ClassElement - * + * * @param element the node * @return processed node, which will replace the original one, or the original node */ diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/visitor/TranslatorNodeVisitor.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/visitor/TranslatorNodeVisitor.java index 44d659896bb..6089c4bd31b 100644 --- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/visitor/TranslatorNodeVisitor.java +++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/visitor/TranslatorNodeVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -60,7 +60,6 @@ import com.oracle.js.parser.ir.ExportSpecifierNode; import com.oracle.js.parser.ir.ExpressionStatement; import com.oracle.js.parser.ir.ForNode; -import com.oracle.js.parser.ir.FromNode; import com.oracle.js.parser.ir.FunctionNode; import com.oracle.js.parser.ir.IdentNode; import com.oracle.js.parser.ir.IfNode; @@ -292,10 +291,6 @@ public R enterForNode(final ForNode forNode) { return enterDefault(forNode); } - public R enterFromNode(final FromNode fromNode) { - return enterDefault(fromNode); - } - /** * Callback for entering a FunctionNode * @@ -536,7 +531,7 @@ public R enterTemplateLiteralNode(final TemplateLiteralNode templateLiteralNode) /** * Callback for entering a ClassElement - * + * * @param element the node */ public R enterClassElement(final ClassElement element) { diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ExportParserTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ExportParserTest.java index fd2df17bb54..bbf7951e464 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ExportParserTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ExportParserTest.java @@ -62,7 +62,6 @@ import com.oracle.js.parser.ir.ExportSpecifierNode; import com.oracle.js.parser.ir.Expression; import com.oracle.js.parser.ir.ExpressionStatement; -import com.oracle.js.parser.ir.FromNode; import com.oracle.js.parser.ir.FunctionNode; import com.oracle.js.parser.ir.IdentNode; import com.oracle.js.parser.ir.LiteralNode; @@ -162,8 +161,7 @@ private static ExportSpecifierNode testFromHelper(String code) { assertEquals(1, exports.size()); ExportNode export = exports.get(0); assertFalse(export.isDefault()); - FromNode from = export.getFrom(); - assertEquals(ImportParserTest.FOO, from.getModuleSpecifier().getValue()); + assertEquals(ImportParserTest.FOO, export.getModuleSpecifier().getValue()); List specifiers = export.getNamedExports().getExportSpecifiers(); assertEquals(1, specifiers.size()); return specifiers.get(0); @@ -176,8 +174,7 @@ public void testFromBatch() { assertEquals(1, exports.size()); ExportNode export = exports.get(0); assertFalse(export.isDefault()); - FromNode from = export.getFrom(); - assertEquals(ImportParserTest.FOO, from.getModuleSpecifier().getValue()); + assertEquals(ImportParserTest.FOO, export.getModuleSpecifier().getValue()); } @Test @@ -218,8 +215,7 @@ public void testFromNamedAsSpecifiers() { assertEquals(1, exports.size()); ExportNode export = exports.get(0); assertFalse(export.isDefault()); - FromNode from = export.getFrom(); - assertEquals(ImportParserTest.FOO, from.getModuleSpecifier().getValue()); + assertEquals(ImportParserTest.FOO, export.getModuleSpecifier().getValue()); List specifiers = export.getNamedExports().getExportSpecifiers(); assertEquals(2, specifiers.size()); @@ -245,8 +241,7 @@ public void testFromSpecifiers() { assertEquals(1, exports.size()); ExportNode export = exports.get(0); assertFalse(export.isDefault()); - FromNode from = export.getFrom(); - assertEquals(ImportParserTest.FOO, from.getModuleSpecifier().getValue()); + assertEquals(ImportParserTest.FOO, export.getModuleSpecifier().getValue()); List specifiers = export.getNamedExports().getExportSpecifiers(); assertEquals(2, specifiers.size()); @@ -269,7 +264,7 @@ public void testExportNamedFromWithAttributes() { assertEquals(1, exports.size()); ExportNode export = exports.get(0); assertFalse(export.isDefault()); - assertEquals(ImportParserTest.FOO, export.getFrom().getModuleSpecifier().getValue()); + assertEquals(ImportParserTest.FOO, export.getModuleSpecifier().getValue()); List specifiers = export.getNamedExports().getExportSpecifiers(); assertEquals(1, specifiers.size()); assertEquals(ImportParserTest.BAR, specifiers.get(0).getIdentifier().getPropertyNameTS()); @@ -295,7 +290,7 @@ public void testExportStarFromWithAttributes() { assertEquals(1, exports.size()); ExportNode export = exports.get(0); assertFalse(export.isDefault()); - assertEquals(ImportParserTest.FOO, export.getFrom().getModuleSpecifier().getValue()); + assertEquals(ImportParserTest.FOO, export.getModuleSpecifier().getValue()); assertEquals(export.toString(), expectedAttributes.size(), export.getAttributes().size()); assertEquals(export.toString(), expectedAttributes, export.getAttributes()); @@ -318,7 +313,7 @@ public void testExportNamespaceFromWithAttributes() { assertEquals(1, exports.size()); ExportNode export = exports.get(0); assertFalse(export.isDefault()); - assertEquals(ImportParserTest.FOO, export.getFrom().getModuleSpecifier().getValue()); + assertEquals(ImportParserTest.FOO, export.getModuleSpecifier().getValue()); assertNull(export.toString(), export.getNamedExports()); assertEquals(export.toString(), ImportParserTest.BAR, export.getExportIdentifier().getPropertyNameTS()); diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ImportParserTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ImportParserTest.java index 3a6ada731d1..1471a7c9010 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ImportParserTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ImportParserTest.java @@ -51,7 +51,6 @@ import com.oracle.js.parser.Parser; import com.oracle.js.parser.ScriptEnvironment; import com.oracle.js.parser.Source; -import com.oracle.js.parser.ir.FromNode; import com.oracle.js.parser.ir.FunctionNode; import com.oracle.js.parser.ir.IdentNode; import com.oracle.js.parser.ir.ImportClauseNode; @@ -85,8 +84,7 @@ public void testDefault() { ImportNode importNode = imports.get(0); IdentNode ident = importNode.getImportClause().getDefaultBinding(); assertEquals(BAR, ident.getNameTS()); - FromNode from = importNode.getFrom(); - assertEquals(FOO, from.getModuleSpecifier().getValue()); + assertEquals(FOO, importNode.getModuleSpecifier().getValue()); } @Test @@ -102,8 +100,7 @@ public void testDefaultAndNamedSpecifiers() { assertEquals(1, specifiers.size()); ImportSpecifierNode specifier = specifiers.get(0); assertEquals(BAR, specifier.getBindingIdentifier().getNameTS()); - FromNode from = importNode.getFrom(); - assertEquals(FOO, from.getModuleSpecifier().getValue()); + assertEquals(FOO, importNode.getModuleSpecifier().getValue()); } @Test @@ -117,8 +114,7 @@ public void testDefaultAndNamespaceSpecifiers() { assertEquals(FOO, ident.getNameTS()); NameSpaceImportNode namespace = clause.getNameSpaceImport(); assertEquals(BAR, namespace.getBindingIdentifier().getNameTS()); - FromNode from = importNode.getFrom(); - assertEquals(FOO, from.getModuleSpecifier().getValue()); + assertEquals(FOO, importNode.getModuleSpecifier().getValue()); } @Test @@ -133,8 +129,7 @@ public void testDefaultAs() { ImportSpecifierNode specifier = specifiers.get(0); assertEquals(FOO, specifier.getBindingIdentifier().getNameTS()); assertEquals(DEFAULT, specifier.getIdentifier().getPropertyNameTS()); - FromNode from = importNode.getFrom(); - assertEquals(FOO, from.getModuleSpecifier().getValue()); + assertEquals(FOO, importNode.getModuleSpecifier().getValue()); } @Test @@ -158,8 +153,7 @@ public void testNamedAsSpecifier() { ImportSpecifierNode specifier = specifiers.get(0); assertEquals(BAZ, specifier.getBindingIdentifier().getNameTS()); assertEquals(BAR, specifier.getIdentifier().getPropertyNameTS()); - FromNode from = importNode.getFrom(); - assertEquals(FOO, from.getModuleSpecifier().getValue()); + assertEquals(FOO, importNode.getModuleSpecifier().getValue()); } @Test @@ -179,8 +173,7 @@ public void testNamedAsSpecifiers() { specifier = specifiers.get(1); assertEquals(XYZ, specifier.getBindingIdentifier().getNameTS()); - FromNode from = importNode.getFrom(); - assertEquals(FOO, from.getModuleSpecifier().getValue()); + assertEquals(FOO, importNode.getModuleSpecifier().getValue()); } @Test @@ -192,8 +185,7 @@ public void testNamedEmpty() { ImportClauseNode clause = importNode.getImportClause(); List specifiers = clause.getNamedImports().getImportSpecifiers(); assertEquals(0, specifiers.size()); - FromNode from = importNode.getFrom(); - assertEquals(FOO, from.getModuleSpecifier().getValue()); + assertEquals(FOO, importNode.getModuleSpecifier().getValue()); } @Test @@ -207,8 +199,7 @@ public void testNamedSpecifier() { assertEquals(1, specifiers.size()); ImportSpecifierNode specifier = specifiers.get(0); assertEquals(BAR, specifier.getBindingIdentifier().getNameTS()); - FromNode from = importNode.getFrom(); - assertEquals(FOO, from.getModuleSpecifier().getValue()); + assertEquals(FOO, importNode.getModuleSpecifier().getValue()); } @Test @@ -227,8 +218,7 @@ public void testNamedSpecifiers() { specifier = specifiers.get(1); assertEquals(BAZ, specifier.getBindingIdentifier().getNameTS()); - FromNode from = importNode.getFrom(); - assertEquals(FOO, from.getModuleSpecifier().getValue()); + assertEquals(FOO, importNode.getModuleSpecifier().getValue()); } @Test @@ -239,8 +229,7 @@ public void testNamespaceSpecifier() { ImportNode importNode = imports.get(0); NameSpaceImportNode namespace = importNode.getImportClause().getNameSpaceImport(); assertEquals(FOO, namespace.getBindingIdentifier().getNameTS()); - FromNode from = importNode.getFrom(); - assertEquals(FOO, from.getModuleSpecifier().getValue()); + assertEquals(FOO, importNode.getModuleSpecifier().getValue()); } @Test @@ -255,8 +244,7 @@ public void testImportNamedWithAttributes() { assertEquals(1, imports.size()); ImportNode importNode = imports.get(0); - FromNode from = importNode.getFrom(); - assertEquals(FOO, from.getModuleSpecifier().getValue()); + assertEquals(FOO, importNode.getModuleSpecifier().getValue()); ImportClauseNode clause = importNode.getImportClause(); List specifiers = clause.getNamedImports().getImportSpecifiers(); assertEquals(1, specifiers.size()); @@ -284,8 +272,7 @@ public void testImportNamespaceWithAttributes() { assertEquals(1, imports.size()); ImportNode importNode = imports.get(0); - FromNode from = importNode.getFrom(); - assertEquals(FOO, from.getModuleSpecifier().getValue()); + assertEquals(FOO, importNode.getModuleSpecifier().getValue()); ImportClauseNode clause = importNode.getImportClause(); NameSpaceImportNode nameSpaceImport = clause.getNameSpaceImport(); assertEquals(BAR, nameSpaceImport.getBindingIdentifier().getNameTS()); From c9d442c6522a2e7c3b9b1afd9a482ffb5d395481 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 8 Aug 2024 20:20:32 +0200 Subject: [PATCH 182/265] Make ModuleRequest immutable and convert it to a record class. --- .../src/com/oracle/js/parser/ir/Module.java | 32 +++++++------------ .../truffle/js/parser/GraalJSEvaluator.java | 18 +++++------ .../js/test/parser/ExportParserTest.java | 12 +++---- .../js/test/parser/ImportParserTest.java | 8 ++--- .../truffle/js/builtins/DebugBuiltins.java | 2 +- .../commonjs/NpmCompatibleESModuleLoader.java | 4 +-- .../nodes/module/ResolveNamedImportNode.java | 8 ++--- .../js/nodes/promise/ImportCallNode.java | 2 +- .../objects/DefaultESModuleLoader.java | 8 ++--- .../truffle/trufflenode/GraalJSAccess.java | 8 ++--- 10 files changed, 45 insertions(+), 57 deletions(-) diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/Module.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/Module.java index bee7f39086f..78880caf070 100644 --- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/Module.java +++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/Module.java @@ -41,13 +41,13 @@ package com.oracle.js.parser.ir; -import com.oracle.js.parser.ParserStrings; -import com.oracle.truffle.api.strings.TruffleString; - import java.util.Collections; import java.util.List; import java.util.Map; +import com.oracle.js.parser.ParserStrings; +import com.oracle.truffle.api.strings.TruffleString; + /** * Module information. */ @@ -175,14 +175,9 @@ public String toString() { } } - public static final class ModuleRequest { - private final TruffleString specifier; - private Map attributes; - - private ModuleRequest(TruffleString specifier, Map attributes) { - this.specifier = specifier; - this.attributes = attributes; - } + public record ModuleRequest( + TruffleString specifier, + Map attributes) { public static ModuleRequest create(TruffleString specifier) { return new ModuleRequest(specifier, Collections.emptyMap()); @@ -196,16 +191,11 @@ public static ModuleRequest create(TruffleString specifier, Map.Entry getAttributes() { - return attributes; - } - - public void setAttributes(Map attributes) { - this.attributes = attributes; + public ModuleRequest withAttributes(Map newAttributes) { + if (this.attributes == newAttributes) { + return this; + } + return new ModuleRequest(specifier, newAttributes); } } diff --git a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java index bfac15d5c7b..db2a6b9b690 100644 --- a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java +++ b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -448,29 +448,27 @@ private void setSyntheticModuleExport(JSModuleRecord module) { @TruffleBoundary @Override public JSModuleRecord hostResolveImportedModule(JSContext context, ScriptOrModule referrer, ModuleRequest moduleRequest) { - filterSupportedImportAttributes(context, moduleRequest); JSModuleLoader moduleLoader = referrer instanceof JSModuleRecord ? ((JSModuleRecord) referrer).getModuleLoader() : JSRealm.get(null).getModuleLoader(); - return moduleLoader.resolveImportedModule(referrer, moduleRequest); + return moduleLoader.resolveImportedModule(referrer, filterSupportedImportAttributes(context, moduleRequest)); } private static JSModuleRecord hostResolveImportedModule(JSModuleRecord referencingModule, ModuleRequest moduleRequest) { - filterSupportedImportAttributes(referencingModule.getContext(), moduleRequest); - return referencingModule.getModuleLoader().resolveImportedModule(referencingModule, moduleRequest); + return referencingModule.getModuleLoader().resolveImportedModule(referencingModule, filterSupportedImportAttributes(referencingModule.getContext(), moduleRequest)); } - private static void filterSupportedImportAttributes(final JSContext context, final ModuleRequest moduleRequest) { - if (moduleRequest.getAttributes().isEmpty()) { - return; + private static ModuleRequest filterSupportedImportAttributes(JSContext context, ModuleRequest moduleRequest) { + if (moduleRequest.attributes().isEmpty() || context.getSupportedImportAttributes().containsAll(moduleRequest.attributes().keySet())) { + return moduleRequest; } Map supportedAttributes = new HashMap<>(); - for (Map.Entry attributes : moduleRequest.getAttributes().entrySet()) { + for (Map.Entry attributes : moduleRequest.attributes().entrySet()) { TruffleString key = attributes.getKey(); TruffleString value = attributes.getValue(); if (context.getSupportedImportAttributes().contains(key)) { supportedAttributes.put(key, value); } } - moduleRequest.setAttributes(supportedAttributes); + return moduleRequest.withAttributes(supportedAttributes); } Collection getExportedNames(JSModuleRecord moduleRecord) { diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ExportParserTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ExportParserTest.java index bbf7951e464..18199e74bfb 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ExportParserTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ExportParserTest.java @@ -274,8 +274,8 @@ public void testExportNamedFromWithAttributes() { assertEquals(1, module.getIndirectExportEntries().size()); ExportEntry exportEntry = module.getIndirectExportEntries().get(0); - assertEquals(exportEntry.toString(), expectedAttributes.size(), exportEntry.getModuleRequest().getAttributes().size()); - assertEquals(exportEntry.toString(), expectedAttributes, exportEntry.getModuleRequest().getAttributes()); + assertEquals(exportEntry.toString(), expectedAttributes.size(), exportEntry.getModuleRequest().attributes().size()); + assertEquals(exportEntry.toString(), expectedAttributes, exportEntry.getModuleRequest().attributes()); } @Test @@ -297,8 +297,8 @@ public void testExportStarFromWithAttributes() { assertEquals(1, module.getStarExportEntries().size()); ExportEntry exportEntry = module.getStarExportEntries().get(0); - assertEquals(exportEntry.toString(), expectedAttributes.size(), exportEntry.getModuleRequest().getAttributes().size()); - assertEquals(exportEntry.toString(), expectedAttributes, exportEntry.getModuleRequest().getAttributes()); + assertEquals(exportEntry.toString(), expectedAttributes.size(), exportEntry.getModuleRequest().attributes().size()); + assertEquals(exportEntry.toString(), expectedAttributes, exportEntry.getModuleRequest().attributes()); } @Test @@ -322,8 +322,8 @@ public void testExportNamespaceFromWithAttributes() { assertEquals(1, module.getIndirectExportEntries().size()); ExportEntry exportEntry = module.getIndirectExportEntries().get(0); - assertEquals(exportEntry.toString(), expectedAttributes.size(), exportEntry.getModuleRequest().getAttributes().size()); - assertEquals(exportEntry.toString(), expectedAttributes, exportEntry.getModuleRequest().getAttributes()); + assertEquals(exportEntry.toString(), expectedAttributes.size(), exportEntry.getModuleRequest().attributes().size()); + assertEquals(exportEntry.toString(), expectedAttributes, exportEntry.getModuleRequest().attributes()); } @Test diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ImportParserTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ImportParserTest.java index 1471a7c9010..5185a2685b5 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ImportParserTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/parser/ImportParserTest.java @@ -256,8 +256,8 @@ public void testImportNamedWithAttributes() { assertEquals(1, module.getImportEntries().size()); ImportEntry importEntry = module.getImportEntries().get(0); - assertEquals(importEntry.toString(), expectedAttributes.size(), importEntry.getModuleRequest().getAttributes().size()); - assertEquals(importEntry.toString(), expectedAttributes, importEntry.getModuleRequest().getAttributes()); + assertEquals(importEntry.toString(), expectedAttributes.size(), importEntry.getModuleRequest().attributes().size()); + assertEquals(importEntry.toString(), expectedAttributes, importEntry.getModuleRequest().attributes()); } @Test @@ -282,7 +282,7 @@ public void testImportNamespaceWithAttributes() { assertEquals(1, module.getImportEntries().size()); ImportEntry importEntry = module.getImportEntries().get(0); - assertEquals(importEntry.toString(), expectedAttributes.size(), importEntry.getModuleRequest().getAttributes().size()); - assertEquals(importEntry.toString(), expectedAttributes, importEntry.getModuleRequest().getAttributes()); + assertEquals(importEntry.toString(), expectedAttributes.size(), importEntry.getModuleRequest().attributes().size()); + assertEquals(importEntry.toString(), expectedAttributes, importEntry.getModuleRequest().attributes()); } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DebugBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DebugBuiltins.java index 99ecc0a77bf..cd8f166f659 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DebugBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DebugBuiltins.java @@ -579,7 +579,7 @@ private Source resolveModuleSource(@SuppressWarnings("unused") ScriptOrModule re @Override public JSModuleRecord resolveImportedModule(ScriptOrModule referencingModule, ModuleRequest moduleRequest) { - return moduleMap.computeIfAbsent(moduleRequest.getSpecifier(), + return moduleMap.computeIfAbsent(moduleRequest.specifier(), (key) -> new JSModuleRecord(evaluator.envParseModule(JSRealm.get(null), resolveModuleSource(referencingModule, key)), this)); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/commonjs/NpmCompatibleESModuleLoader.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/commonjs/NpmCompatibleESModuleLoader.java index acffe4cdb17..b911f77a9a8 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/commonjs/NpmCompatibleESModuleLoader.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/commonjs/NpmCompatibleESModuleLoader.java @@ -122,7 +122,7 @@ private NpmCompatibleESModuleLoader(JSRealm realm) { @TruffleBoundary @Override public JSModuleRecord resolveImportedModule(ScriptOrModule referencingModule, ModuleRequest moduleRequest) { - String specifier = moduleRequest.getSpecifier().toJavaStringUncached(); + String specifier = moduleRequest.specifier().toJavaStringUncached(); log("IMPORT resolve ", specifier); String moduleReplacementName = getCoreModuleReplacement(realm, specifier); if (moduleReplacementName != null) { @@ -157,7 +157,7 @@ public JSModuleRecord resolveImportedModule(ScriptOrModule referencingModule, Mo } private JSModuleRecord loadCoreModuleReplacement(ScriptOrModule referencingModule, ModuleRequest moduleRequest, String moduleReplacementName) { - String specifier = moduleRequest.getSpecifier().toJavaStringUncached(); + String specifier = moduleRequest.specifier().toJavaStringUncached(); log("IMPORT resolve built-in ", specifier); JSModuleRecord existingModule = moduleMap.get(specifier); if (existingModule != null) { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveNamedImportNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveNamedImportNode.java index d1d6dcaa7b0..caf5aedcd24 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveNamedImportNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveNamedImportNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -40,6 +40,8 @@ */ package com.oracle.truffle.js.nodes.module; +import java.util.Set; + import com.oracle.js.parser.ir.Module; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.Tag; @@ -54,8 +56,6 @@ import com.oracle.truffle.js.runtime.objects.ExportResolution; import com.oracle.truffle.js.runtime.objects.JSModuleRecord; -import java.util.Set; - /** * Resolves a named import binding and writes the resolved binding into the frame. Throws a * SyntaxError if the imported binding could not be found or was ambiguous. @@ -93,7 +93,7 @@ public Object execute(VirtualFrame frame) { // If resolution is null or resolution is "ambiguous", throw SyntaxError. if (resolution.isNull() || resolution.isAmbiguous()) { String message = "The requested module '%s' does not provide an export named '%s'"; - throw Errors.createSyntaxErrorFormat(message, this, moduleRequest.getSpecifier(), importName); + throw Errors.createSyntaxErrorFormat(message, this, moduleRequest.specifier(), importName); } Object resolutionOrNamespace; if (resolution.isNamespace()) { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java index 84add74e086..ab4283b703f 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java @@ -239,7 +239,7 @@ public final JSDynamicObject hostImportModuleDynamically(ScriptOrModule referenc if (context.hasImportModuleDynamicallyCallbackBeenSet()) { JSDynamicObject promise = context.hostImportModuleDynamically(realm, referencingScriptOrModule, moduleRequest); if (promise == null) { - return rejectPromise(promiseCapability, createTypeErrorCannotImport(moduleRequest.getSpecifier())); + return rejectPromise(promiseCapability, createTypeErrorCannotImport(moduleRequest.specifier())); } assert JSPromise.isJSPromise(promise); return promise; diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java index 08cae299d9f..6d777ec1f28 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java @@ -105,7 +105,7 @@ public JSModuleRecord resolveImportedModule(ScriptOrModule referrer, ModuleReque refPathOrName = refPath != null ? refPath : referrerSource.getName(); } try { - TruffleString specifierTS = moduleRequest.getSpecifier(); + TruffleString specifierTS = moduleRequest.specifier(); String specifier = Strings.toJavaString(specifierTS); TruffleFile moduleFile; String canonicalPath; @@ -205,8 +205,8 @@ protected JSModuleRecord loadModuleFromUrl(ScriptOrModule referrer, ModuleReques return existingModule; } - Source source = Source.newBuilder(JavaScriptLanguage.ID, moduleFile).name(Strings.toJavaString(moduleRequest.getSpecifier())).mimeType(JavaScriptLanguage.MODULE_MIME_TYPE).build(); - Map attributes = moduleRequest.getAttributes(); + Source source = Source.newBuilder(JavaScriptLanguage.ID, moduleFile).name(Strings.toJavaString(moduleRequest.specifier())).mimeType(JavaScriptLanguage.MODULE_MIME_TYPE).build(); + Map attributes = moduleRequest.attributes(); int moduleType = getModuleType(moduleFile.getName()); TruffleString assertedType = attributes.get(JSContext.getTypeImportAttribute()); if (!doesModuleTypeMatchAssertionType(assertedType, moduleType)) { @@ -222,7 +222,7 @@ protected JSModuleRecord loadModuleFromUrl(ScriptOrModule referrer, ModuleReques moduleMap.put(canonicalPath, newModule); if (referrer != null) { - referrer.rememberImportedModuleSource(moduleRequest.getSpecifier(), source); + referrer.rememberImportedModuleSource(moduleRequest.specifier(), source); } return newModule; } diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java index ca5d62385a3..a80b86b64f8 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java @@ -3365,7 +3365,7 @@ public JSDynamicObject importModuleDynamically(JSRealm realm, ScriptOrModule ref resourceName = Strings.fromJavaString(referrer.getSource().getName()); hostDefinedOptions = graalJSAccess.scriptOrModuleGetHostDefinedOptions(referrer); } - return (JSDynamicObject) NativeAccess.executeImportModuleDynamicallyCallback(realm, hostDefinedOptions, resourceName, moduleRequest.getSpecifier(), importAssertions); + return (JSDynamicObject) NativeAccess.executeImportModuleDynamicallyCallback(realm, hostDefinedOptions, resourceName, moduleRequest.specifier(), importAssertions); } } @@ -3910,12 +3910,12 @@ public Object moduleCreateSyntheticModule(Object moduleName, Object[] exportName } public Object moduleRequestGetSpecifier(Object moduleRequest) { - return ((ModuleRequest) moduleRequest).getSpecifier(); + return ((ModuleRequest) moduleRequest).specifier(); } private static Object[] moduleRequestGetImportAssertionsImpl(ModuleRequest request, boolean withSourceOffset) { List attributes = new ArrayList<>(); - for (Map.Entry entry : request.getAttributes().entrySet()) { + for (Map.Entry entry : request.attributes().entrySet()) { attributes.add(entry.getKey()); attributes.add(entry.getValue()); if (withSourceOffset) { @@ -4249,7 +4249,7 @@ void setResolver(long resolver) { @Override public JSModuleRecord resolveImportedModule(ScriptOrModule referrer, ModuleRequest moduleRequest) { Map referrerCache = cache.get(referrer); - TruffleString specifier = moduleRequest.getSpecifier(); + TruffleString specifier = moduleRequest.specifier(); if (referrerCache == null) { referrerCache = new HashMap<>(); cache.put(referrer, referrerCache); From a1bd35406364b21d8e3b6157975774596ccfa439 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Fri, 9 Aug 2024 00:05:31 +0200 Subject: [PATCH 183/265] Refactor module loading, implementing HostLoadImportModule and LoadRequestedModules. --- .../truffle/js/parser/GraalJSEvaluator.java | 157 +++++++++++- .../truffle/js/builtins/DebugBuiltins.java | 7 +- .../nodes/module/ResolveNamedImportNode.java | 7 +- .../nodes/module/ResolveStarImportNode.java | 12 +- .../js/nodes/promise/ImportCallNode.java | 233 +++++++++--------- .../nodes/promise/PromiseReactionJobNode.java | 2 +- .../promise/TriggerPromiseReactionsNode.java | 5 +- .../oracle/truffle/js/runtime/Evaluator.java | 7 +- .../oracle/truffle/js/runtime/JSContext.java | 6 +- .../objects/DefaultESModuleLoader.java | 6 +- .../js/runtime/objects/JSModuleLoader.java | 8 +- .../js/runtime/objects/JSModuleRecord.java | 32 ++- .../js/runtime/objects/ScriptOrModule.java | 15 +- .../truffle/trufflenode/GraalJSAccess.java | 18 +- 14 files changed, 357 insertions(+), 158 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java index db2a6b9b690..28c62839f3b 100644 --- a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java +++ b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java @@ -91,6 +91,7 @@ import com.oracle.truffle.js.nodes.function.EvalNode; import com.oracle.truffle.js.nodes.function.FunctionRootNode; import com.oracle.truffle.js.nodes.function.JSBuiltin; +import com.oracle.truffle.js.nodes.promise.ImportCallNode; import com.oracle.truffle.js.nodes.promise.NewPromiseCapabilityNode; import com.oracle.truffle.js.nodes.promise.PerformPromiseThenNode; import com.oracle.truffle.js.parser.date.DateParser; @@ -113,7 +114,9 @@ import com.oracle.truffle.js.runtime.builtins.JSFunctionObject; import com.oracle.truffle.js.runtime.builtins.JSModuleNamespace; import com.oracle.truffle.js.runtime.builtins.JSModuleNamespaceObject; +import com.oracle.truffle.js.runtime.builtins.JSPromise; import com.oracle.truffle.js.runtime.builtins.JSPromiseObject; +import com.oracle.truffle.js.runtime.objects.Completion; import com.oracle.truffle.js.runtime.objects.ExportResolution; import com.oracle.truffle.js.runtime.objects.JSDynamicObject; import com.oracle.truffle.js.runtime.objects.JSModuleData; @@ -289,7 +292,17 @@ public Object execute(VirtualFrame frame) { @TruffleBoundary private Object evalModule(JSRealm realm) { - JSModuleRecord moduleRecord = realm.getModuleLoader().loadModule(source, parsedModule); + JSModuleRecord moduleRecord = new JSModuleRecord(parsedModule, realm.getModuleLoader()); + ModuleRequest moduleRequest = ModuleRequest.create(Strings.fromJavaString(source.getName())); + realm.getModuleLoader().addLoadedModule(moduleRequest, moduleRecord); + + JSPromiseObject loadPromise = (JSPromiseObject) loadRequestedModules(realm, moduleRecord, Undefined.instance).getPromise(); + assert !JSPromise.isPending(loadPromise); + // If loading failed, we must not perform module linking. + if (JSPromise.isRejected(loadPromise)) { + throw JSRuntime.getException(loadPromise.getPromiseResult(), this); + } + moduleLinking(realm, moduleRecord); Object promise = moduleEvaluation(realm, moduleRecord); boolean isAsync = context.isOptionTopLevelAwait() && moduleRecord.isAsyncEvaluation(); @@ -600,10 +613,131 @@ public JSDynamicObject getModuleNamespace(JSModuleRecord moduleRecord) { return namespace; } + private static class GraphLoadingState { + boolean isLoading; + int pendingModulesCount; + PromiseCapabilityRecord promiseCapability; + Object hostDefined; + Set visited; + + GraphLoadingState(PromiseCapabilityRecord promiseCapability, Object hostDefined) { + this.isLoading = true; + this.pendingModulesCount = 1; + this.promiseCapability = promiseCapability; + this.hostDefined = hostDefined; + this.visited = new HashSet<>(); + } + } + + @TruffleBoundary + @Override + public PromiseCapabilityRecord loadRequestedModules(JSRealm realm, JSModuleRecord moduleRecord, Object hostDefined) { + PromiseCapabilityRecord pc = NewPromiseCapabilityNode.createDefault(realm); + GraphLoadingState state = new GraphLoadingState(pc, hostDefined); + try { + innerModuleLoading(realm, state, moduleRecord); + } catch (AbstractTruffleException e) { + assert false : e; // should not throw + throw e; + } + return pc; + } + + private void innerModuleLoading(JSRealm realm, GraphLoadingState state, JSModuleRecord moduleRecord) { + assert state.isLoading; + if (moduleRecord.getStatus() == Status.New && !state.visited.contains(moduleRecord)) { + state.visited.add(moduleRecord); + int requestedModuleCount = moduleRecord.getModule().getRequestedModules().size(); + state.pendingModulesCount += requestedModuleCount; + for (var required : moduleRecord.getModule().getRequestedModules()) { + JSModuleRecord resolved = moduleRecord.getLoadedModule(realm, required); + if (resolved != null) { + innerModuleLoading(realm, state, resolved); + } else { + hostLoadImportedModule(realm, moduleRecord, required, state.hostDefined, state); + } + if (!state.isLoading) { + return; + } + } + } + assert state.pendingModulesCount >= 1 : state.pendingModulesCount; + if (--state.pendingModulesCount == 0) { + state.isLoading = false; + for (var loaded : state.visited) { + loaded.setUnlinked(); + } + JSFunction.call(JSArguments.createOneArg(Undefined.instance, state.promiseCapability.getResolve(), Undefined.instance)); + } + } + + /** + * HostLoadImportedModule takes arguments referrer (a Script Record, a Cyclic Module Record, or + * a Realm Record), specifier (a String), hostDefined (anything), and payload (a + * GraphLoadingState Record or a PromiseCapability Record) and returns unused. + * + * The host environment must perform FinishLoadingImportedModule(referrer, specifier, payload, + * result), where result is either a normal completion containing the loaded Module Record or a + * throw completion, either synchronously or asynchronously. + */ + @Override + public void hostLoadImportedModule(JSRealm realm, ScriptOrModule referrer, ModuleRequest moduleRequest, Object hostDefined, Object payload) { + Completion moduleCompletion; + try { + JSModuleRecord module = hostResolveImportedModule(realm.getContext(), referrer, moduleRequest); + moduleCompletion = Completion.forNormal(module); + } catch (AbstractTruffleException e) { + moduleCompletion = Completion.forThrow(getErrorObject(e)); + } + finishLoadingImportedModule(realm, referrer, moduleRequest, payload, moduleCompletion); + } + + private void finishLoadingImportedModule(JSRealm realm, ScriptOrModule referrer, ModuleRequest moduleRequest, Object payload, Completion moduleCompletion) { + if (moduleCompletion.isNormal()) { + JSModuleRecord moduleResult = (JSModuleRecord) moduleCompletion.getValue(); + JSModuleRecord existing = referrer != null + ? referrer.addLoadedModule(realm, moduleRequest, moduleResult) + : realm.getModuleLoader().addLoadedModule(moduleRequest, moduleResult); + if (existing != null) { + assert existing == moduleResult; + } + } + if (payload instanceof GraphLoadingState state) { + continueModuleLoading(realm, state, moduleCompletion); + } else { + continueDynamicImport(payload, moduleCompletion); + } + } + + private void continueModuleLoading(JSRealm realm, GraphLoadingState state, Completion moduleCompletion) { + if (!state.isLoading) { + return; + } + if (moduleCompletion.isNormal()) { + innerModuleLoading(realm, state, (JSModuleRecord) moduleCompletion.getValue()); + } else { + state.isLoading = false; + JSFunction.call(JSArguments.createOneArg(Undefined.instance, state.promiseCapability.getReject(), moduleCompletion.getValue())); + } + } + + private static void continueDynamicImport(Object payload, Completion moduleCompletion) { + var continuation = (ImportCallNode.ContinueDynamicImportPayload) payload; + PromiseCapabilityRecord promiseCapability = continuation.promiseCapability(); + if (moduleCompletion.isAbrupt()) { + JSFunction.call(JSArguments.createOneArg(Undefined.instance, promiseCapability.getReject(), moduleCompletion.getValue())); + return; + } + + JSModuleRecord module = (JSModuleRecord) moduleCompletion.getValue(); + // Perform the remaining steps of ContinueDynamicImport. + JSFunction.call(JSArguments.create(Undefined.instance, continuation.continueDynamicImportCallback(), promiseCapability, module)); + } + @TruffleBoundary @Override public void moduleLinking(JSRealm realm, JSModuleRecord moduleRecord) { - assert moduleRecord.getStatus() != Status.Linking && moduleRecord.getStatus() != Status.Evaluating; + assert moduleRecord.getStatus() != Status.Linking && moduleRecord.getStatus() != Status.Evaluating && moduleRecord.getStatus() != Status.New : moduleRecord.getStatus(); Deque stack = new ArrayDeque<>(4); try { @@ -631,7 +765,7 @@ private int innerModuleLinking(JSRealm realm, JSModuleRecord moduleRecord, Deque moduleRecord.getStatus() == Status.Evaluated) { return index; } - assert moduleRecord.getStatus() == Status.Unlinked; + assert moduleRecord.getStatus() == Status.Unlinked : moduleRecord.getStatus(); moduleRecord.setStatus(Status.Linking); moduleRecord.setDFSIndex(index); moduleRecord.setDFSAncestorIndex(index); @@ -690,7 +824,7 @@ public Object moduleEvaluation(JSRealm realm, JSModuleRecord moduleRecord) { JSModuleRecord module = moduleRecord; Deque stack = new ArrayDeque<>(4); if (realm.getContext().isOptionTopLevelAwait()) { - assert module.getStatus() == Status.Linked || module.getStatus() == Status.EvaluatingAsync || module.getStatus() == Status.Evaluated; + assert module.getStatus() == Status.Linked || module.getStatus() == Status.EvaluatingAsync || module.getStatus() == Status.Evaluated : module.getStatus(); if (module.getStatus() == Status.EvaluatingAsync || module.getStatus() == Status.Evaluated) { module = module.getCycleRoot(); } @@ -736,6 +870,18 @@ private static void handleModuleEvaluationError(JSModuleRecord module, Deque new JSModuleRecord(evaluator.envParseModule(JSRealm.get(null), resolveModuleSource(referencingModule, key)), this)); } - - @Override - public JSModuleRecord loadModule(Source moduleSource, JSModuleData moduleData) { - throw new UnsupportedOperationException(); - } }; JSModuleRecord module = moduleLoader.resolveImportedModule(null, ModuleRequest.create(name)); JSRealm realm = getRealm(); + evaluator.loadRequestedModules(realm, module, Undefined.instance); evaluator.moduleLinking(realm, module); evaluator.moduleEvaluation(realm, module); return Strings.fromJavaString(String.valueOf(module)); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveNamedImportNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveNamedImportNode.java index caf5aedcd24..2bd0a6bf2bd 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveNamedImportNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveNamedImportNode.java @@ -85,10 +85,11 @@ public static StatementNode create(JSContext context, JavaScriptNode moduleNode, @Override public Object execute(VirtualFrame frame) { - JSModuleRecord referencingScriptOrModule = (JSModuleRecord) moduleNode.execute(frame); + JSModuleRecord referrer = (JSModuleRecord) moduleNode.execute(frame); Evaluator evaluator = context.getEvaluator(); - JSModuleRecord importedModule = evaluator.hostResolveImportedModule(context, referencingScriptOrModule, moduleRequest); - // Let resolution be importedModule.ResolveExport(in.[[ImportName]], << >>, << >>). + // Let importedModule be GetImportedModule(module, in.[[ModuleRequest]]). + JSModuleRecord importedModule = referrer.getImportedModule(moduleRequest); + // Let resolution be importedModule.ResolveExport(in.[[ImportName]]). ExportResolution resolution = resolutionProfile.profile(evaluator.resolveExport(importedModule, importName)); // If resolution is null or resolution is "ambiguous", throw SyntaxError. if (resolution.isNull() || resolution.isAmbiguous()) { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveStarImportNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveStarImportNode.java index 22c5b3b5a6a..0d086bba836 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveStarImportNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveStarImportNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -48,7 +48,6 @@ import com.oracle.truffle.js.nodes.JavaScriptNode; import com.oracle.truffle.js.nodes.access.JSWriteFrameSlotNode; import com.oracle.truffle.js.nodes.control.StatementNode; -import com.oracle.truffle.js.runtime.Evaluator; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.objects.JSDynamicObject; import com.oracle.truffle.js.runtime.objects.JSModuleRecord; @@ -77,11 +76,12 @@ public static StatementNode create(JSContext context, JavaScriptNode moduleNode, @Override public Object execute(VirtualFrame frame) { - JSModuleRecord referencingScriptOrModule = (JSModuleRecord) moduleNode.execute(frame); - Evaluator evaluator = context.getEvaluator(); - JSModuleRecord importedModule = evaluator.hostResolveImportedModule(context, referencingScriptOrModule, moduleRequest); + JSModuleRecord referrer = (JSModuleRecord) moduleNode.execute(frame); + // Let importedModule be GetImportedModule(module, in.[[ModuleRequest]]). + JSModuleRecord importedModule = referrer.getImportedModule(moduleRequest); + // If in.[[ImportName]] is namespace-object, then // Let namespace be GetModuleNamespace(importedModule) - JSDynamicObject namespace = evaluator.getModuleNamespace(importedModule); + JSDynamicObject namespace = context.getEvaluator().getModuleNamespace(importedModule); // envRec.CreateImmutableBinding(in.[[LocalName]], true). // Call envRec.InitializeBinding(in.[[LocalName]], namespace). writeLocalNode.executeWrite(frame, namespace); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java index ab4283b703f..d75a4932b00 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java @@ -72,7 +72,6 @@ import com.oracle.truffle.js.runtime.JSRuntime; import com.oracle.truffle.js.runtime.JavaScriptRealmBoundaryRootNode; import com.oracle.truffle.js.runtime.JavaScriptRootNode; -import com.oracle.truffle.js.runtime.JobCallback; import com.oracle.truffle.js.runtime.Strings; import com.oracle.truffle.js.runtime.builtins.JSFunction; import com.oracle.truffle.js.runtime.builtins.JSFunctionData; @@ -83,7 +82,6 @@ import com.oracle.truffle.js.runtime.objects.JSModuleRecord; import com.oracle.truffle.js.runtime.objects.JSObject; import com.oracle.truffle.js.runtime.objects.PromiseCapabilityRecord; -import com.oracle.truffle.js.runtime.objects.PromiseReactionRecord; import com.oracle.truffle.js.runtime.objects.ScriptOrModule; import com.oracle.truffle.js.runtime.objects.Undefined; import com.oracle.truffle.js.runtime.util.UnmodifiableArrayList; @@ -93,7 +91,8 @@ */ public class ImportCallNode extends JavaScriptNode { - private static final HiddenKey CURRENT_MODULE_RECORD_KEY = new HiddenKey("%currentModuleRecord"); + private static final HiddenKey PROMISE_CAPABILITY_KEY = new HiddenKey("%promiseCapability"); + private static final HiddenKey LINK_AND_EVALUATE_KEY = new HiddenKey("%linkAndEvaluate"); private static final TruffleString ASSERT = Strings.constant("assert"); @Child private JavaScriptNode argRefNode; @@ -244,7 +243,8 @@ public final JSDynamicObject hostImportModuleDynamically(ScriptOrModule referenc assert JSPromise.isJSPromise(promise); return promise; } else { - context.enqueuePromiseJob(realm, createImportModuleDynamicallyJob(referencingScriptOrModule, moduleRequest, promiseCapability, realm)); + var payload = new ContinueDynamicImportPayload(promiseCapability, createContinueDynamicImportHandler(realm)); + context.getEvaluator().hostLoadImportedModule(realm, referencingScriptOrModule, moduleRequest, Undefined.instance, payload); return promiseCapability.getPromise(); } } @@ -282,113 +282,122 @@ private static JSException createTypeErrorCannotImport(TruffleString specifier) } /** - * Arguments to HostLoadImportedModule. + * Payload to be passed via HostLoadImportedModule to FinishLoadingImportedModule. */ - private record LoadImportedModuleRequest( - ScriptOrModule referencingScriptOrModule, - ModuleRequest moduleRequest, - PromiseCapabilityRecord promiseCapability) { + public record ContinueDynamicImportPayload( + PromiseCapabilityRecord promiseCapability, + JSFunctionObject continueDynamicImportCallback) { } /** - * Returns a promise job that performs both HostImportModuleDynamically and FinishDynamicImport. + * Captures of linkAndEvaluateClosure. */ - public JSFunctionObject createImportModuleDynamicallyJob(ScriptOrModule referencingScriptOrModule, ModuleRequest moduleRequest, PromiseCapabilityRecord promiseCapability, JSRealm realm) { - JobCallback importModuleDynamicallyHandler = realm.getAgent().hostMakeJobCallback(createImportModuleDynamicallyHandler(realm)); - if (context.isOptionTopLevelAwait()) { - LoadImportedModuleRequest request = new LoadImportedModuleRequest(referencingScriptOrModule, moduleRequest, promiseCapability); - return promiseReactionJobNode.execute(PromiseReactionRecord.create(null, importModuleDynamicallyHandler, true), request); - } else { - LoadImportedModuleRequest request = new LoadImportedModuleRequest(referencingScriptOrModule, moduleRequest, null); - return promiseReactionJobNode.execute(PromiseReactionRecord.create(promiseCapability, importModuleDynamicallyHandler, true), request); - } + private record LinkAndEvaluateArgs( + JSModuleRecord moduleRecord, + PromiseCapabilityRecord promiseCapability, + JSFunctionObject onRejected) { } /** - * Returns a handler function to be used together with a PromiseReactionJob in order to perform - * the steps of both HostImportModuleDynamically and FinishDynamicImport. + * Compilable helper function used to implement ContinueDynamicImport; it is passed as the + * payload to HostLoadImportedModule together with the promiseCapability, and will be called + * with the module result on normal completion. */ - private JSFunctionObject createImportModuleDynamicallyHandler(JSRealm realm) { - JSFunctionData functionData = context.getOrCreateBuiltinFunctionData(BuiltinFunctionKey.ImportModuleDynamically, (c) -> createImportModuleDynamicallyHandlerImpl(c)); + private JSFunctionObject createContinueDynamicImportHandler(JSRealm realm) { + JSFunctionData functionData = context.getOrCreateBuiltinFunctionData(BuiltinFunctionKey.ContinueDynamicImport, (c) -> createContinueDynamicImportHandlerImpl(c)); return JSFunction.create(realm, functionData); } - private static JSFunctionData createImportModuleDynamicallyHandlerImpl(JSContext context) { - class ImportModuleDynamicallyRootNode extends JavaScriptRealmBoundaryRootNode implements AsyncHandlerRootNode { - @Child protected JavaScriptNode argumentNode = AccessIndexedArgumentNode.create(0); + /** + * Handles ContinueDynamicImport with normal module completion. + */ + private static JSFunctionData createContinueDynamicImportHandlerImpl(JSContext context) { + class ContinueDynamicImportRootNode extends JavaScriptRealmBoundaryRootNode { + @Child protected JavaScriptNode promiseCapabilityArgument = AccessIndexedArgumentNode.create(0); + @Child protected JavaScriptNode moduleRecordArgument = AccessIndexedArgumentNode.create(1); + + @Child private PerformPromiseThenNode promiseThenNode = PerformPromiseThenNode.create(context); + @Child private PropertySetNode setPromiseCapability = PropertySetNode.createSetHidden(PROMISE_CAPABILITY_KEY, context); + @Child private PropertySetNode setLinkAndEvaluateCaptures = PropertySetNode.createSetHidden(LINK_AND_EVALUATE_KEY, context); - protected ImportModuleDynamicallyRootNode(JavaScriptLanguage lang) { + protected ContinueDynamicImportRootNode(JavaScriptLanguage lang) { super(lang); } @Override public Object executeInRealm(VirtualFrame frame) { - LoadImportedModuleRequest request = (LoadImportedModuleRequest) argumentNode.execute(frame); - ScriptOrModule referencingScriptOrModule = request.referencingScriptOrModule(); - ModuleRequest moduleRequest = request.moduleRequest(); - JSModuleRecord moduleRecord = context.getEvaluator().hostResolveImportedModule(context, referencingScriptOrModule, moduleRequest); - return finishDynamicImport(getRealm(), moduleRecord, referencingScriptOrModule, moduleRequest); + PromiseCapabilityRecord importPromiseCapability = (PromiseCapabilityRecord) promiseCapabilityArgument.execute(frame); + JSModuleRecord module = (JSModuleRecord) moduleRecordArgument.execute(frame); + JSRealm realm = getRealm(); + + JSPromiseObject loadPromise = (JSPromiseObject) context.getEvaluator().loadRequestedModules(realm, module, Undefined.instance).getPromise(); + JSFunctionObject onRejected = createOnRejectedClosure(context, realm, importPromiseCapability); + JSFunctionObject linkAndEvaluate = createLinkAndEvaluateClosure(context, realm, module, importPromiseCapability, onRejected); + + promiseThenNode.execute(loadPromise, linkAndEvaluate, onRejected); + return Undefined.instance; } - protected Object finishDynamicImport(JSRealm realm, JSModuleRecord moduleRecord, ScriptOrModule referencingScriptOrModule, ModuleRequest moduleRequest) { - context.getEvaluator().moduleLinking(realm, moduleRecord); - context.getEvaluator().moduleEvaluation(realm, moduleRecord); - if (moduleRecord.getEvaluationError() != null) { - throw JSRuntime.rethrow(moduleRecord.getEvaluationError()); - } - // Note: PromiseReactionJob performs the promise rejection and resolution. - assert moduleRecord == context.getEvaluator().hostResolveImportedModule(context, referencingScriptOrModule, moduleRequest); - // Evaluate has already been invoked on moduleRecord and successfully completed. - assert moduleRecord.hasBeenEvaluated(); - return context.getEvaluator().getModuleNamespace(moduleRecord); + private JSFunctionObject createOnRejectedClosure(JSContext cx, JSRealm realm, PromiseCapabilityRecord promiseCapability) { + JSFunctionData functionData = cx.getOrCreateBuiltinFunctionData(BuiltinFunctionKey.ContinueDynamicImportRejectedClosure, (c) -> createOnRejectedImpl(c)); + JSFunctionObject rejectedClosure = JSFunction.create(realm, functionData); + setPromiseCapability.setValue(rejectedClosure, promiseCapability); + return rejectedClosure; } - @Override - public AsyncStackTraceInfo getAsyncStackTraceInfo(JSFunctionObject handlerFunction, Object argument) { - if (argument instanceof LoadImportedModuleRequest request) { - return new AsyncStackTraceInfo(request.promiseCapability().getPromise(), null); - } - return new AsyncStackTraceInfo(); + private JSFunctionObject createLinkAndEvaluateClosure(JSContext cx, JSRealm realm, JSModuleRecord module, PromiseCapabilityRecord promiseCapability, JSFunctionObject onRejected) { + JSFunctionData functionData = cx.getOrCreateBuiltinFunctionData(BuiltinFunctionKey.ContinueDynamicImportLinkAndEvaluateClosure, (c) -> createLinkAndEvaluateImpl(c)); + JSFunctionObject linkAndEvaluateClosure = JSFunction.create(realm, functionData); + setLinkAndEvaluateCaptures.setValue(linkAndEvaluateClosure, new LinkAndEvaluateArgs(module, promiseCapability, onRejected)); + return linkAndEvaluateClosure; } } - class TopLevelAwaitImportModuleDynamicallyRootNode extends ImportModuleDynamicallyRootNode { + JavaScriptRootNode root = new ContinueDynamicImportRootNode(context.getLanguage()); + return JSFunctionData.createCallOnly(context, root.getCallTarget(), 0, Strings.EMPTY_STRING); + } + + private static JSFunctionData createLinkAndEvaluateImpl(JSContext context) { + class LinkAndEvaluateRootNode extends JavaScriptRealmBoundaryRootNode { + + @Child private PropertyGetNode getCaptures = PropertyGetNode.createGetHidden(LINK_AND_EVALUATE_KEY, context); + @Child private PropertySetNode setCaptures = PropertySetNode.createSetHidden(LINK_AND_EVALUATE_KEY, context); + @Child private PerformPromiseThenNode promiseThenNode = PerformPromiseThenNode.create(context); @Child private JSFunctionCallNode callPromiseResolve = JSFunctionCallNode.createCall(); @Child private JSFunctionCallNode callPromiseReject; @Child private TryCatchNode.GetErrorObjectNode getErrorObjectNode; - @Child private PropertySetNode setModuleRecord; - protected TopLevelAwaitImportModuleDynamicallyRootNode(JavaScriptLanguage lang) { + protected LinkAndEvaluateRootNode(JavaScriptLanguage lang) { super(lang); } @Override - public Object executeInRealm(VirtualFrame frame) { - LoadImportedModuleRequest request = (LoadImportedModuleRequest) argumentNode.execute(frame); - ScriptOrModule referencingScriptOrModule = request.referencingScriptOrModule(); - ModuleRequest moduleRequest = request.moduleRequest(); - PromiseCapabilityRecord importPromiseCapability = request.promiseCapability(); + protected Object executeInRealm(VirtualFrame frame) { + JSDynamicObject thisFunction = (JSDynamicObject) JSArguments.getFunctionObject(frame.getArguments()); + LinkAndEvaluateArgs captures = (LinkAndEvaluateArgs) getCaptures.getValue(thisFunction); + JSModuleRecord moduleRecord = captures.moduleRecord; + PromiseCapabilityRecord importPromiseCapability = captures.promiseCapability; + JSFunctionObject onRejected = captures.onRejected; + + JSRealm realm = getRealm(); + assert realm == JSFunction.getRealm(JSFrameUtil.getFunctionObject(frame)); try { - JSRealm realm = getRealm(); - assert realm == JSFunction.getRealm(JSFrameUtil.getFunctionObject(frame)); - JSModuleRecord moduleRecord = context.getEvaluator().hostResolveImportedModule(context, referencingScriptOrModule, moduleRequest); - if (moduleRecord.hasTLA()) { - context.getEvaluator().moduleLinking(realm, moduleRecord); - JSPromiseObject evaluatePromise = (JSPromiseObject) context.getEvaluator().moduleEvaluation(realm, moduleRecord); - JSDynamicObject resolve = createFinishDynamicImportCapabilityCallback(context, realm, moduleRecord, false); - JSDynamicObject reject = createFinishDynamicImportCapabilityCallback(context, realm, moduleRecord, true); - promiseThenNode.execute(evaluatePromise, resolve, reject, importPromiseCapability); + // If link is an abrupt completion, reject the promise from import(). + context.getEvaluator().moduleLinking(realm, moduleRecord); + + // Evaluate() should always return a promise. + // Yet, if top-level-await is disabled, returns/throws the result instead. + Object evaluatePromise = context.getEvaluator().moduleEvaluation(realm, moduleRecord); + if (context.isOptionTopLevelAwait()) { + assert evaluatePromise instanceof JSPromiseObject : evaluatePromise; + JSFunctionObject onFulfilled = createFulfilledClosure(context, realm, captures); + promiseThenNode.execute((JSPromiseObject) evaluatePromise, onFulfilled, onRejected); } else { - Object result = finishDynamicImport(realm, moduleRecord, referencingScriptOrModule, moduleRequest); - if (moduleRecord.isAsyncEvaluation()) { - // Some module import started an async loading chain. The top-level - // capability will reject/resolve the dynamic import promise. - JSPromiseObject evaluatePromise = (JSPromiseObject) moduleRecord.getTopLevelCapability().getPromise(); - promiseThenNode.execute(evaluatePromise, importPromiseCapability.getResolve(), importPromiseCapability.getReject(), null); - } else { - callPromiseResolve.executeCall(JSArguments.create(Undefined.instance, importPromiseCapability.getResolve(), result)); - } + // Rethrow any previous execution errors. + moduleRecord.getExecutionResultOrThrow(); + var namespace = context.getEvaluator().getModuleNamespace(moduleRecord); + callPromiseResolve.executeCall(JSArguments.createOneArg(Undefined.instance, importPromiseCapability.getResolve(), namespace)); } } catch (AbstractTruffleException ex) { rejectPromise(importPromiseCapability, ex); @@ -396,6 +405,13 @@ public Object executeInRealm(VirtualFrame frame) { return Undefined.instance; } + private JSFunctionObject createFulfilledClosure(JSContext cx, JSRealm realm, LinkAndEvaluateArgs captures) { + JSFunctionData functionData = cx.getOrCreateBuiltinFunctionData(BuiltinFunctionKey.ContinueDynamicImportFulfilledClosure, (c) -> createOnFulfilledImpl(c)); + JSFunctionObject closure = JSFunction.create(realm, functionData); + setCaptures.setValue(closure, captures); + return closure; + } + private void rejectPromise(PromiseCapabilityRecord moduleLoadedCapability, AbstractTruffleException ex) { if (getErrorObjectNode == null || callPromiseReject == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -403,54 +419,51 @@ private void rejectPromise(PromiseCapabilityRecord moduleLoadedCapability, Abstr callPromiseReject = insert(JSFunctionCallNode.createCall()); } Object errorObject = getErrorObjectNode.execute(ex); - callPromiseReject.executeCall(JSArguments.create(Undefined.instance, moduleLoadedCapability.getReject(), errorObject)); - } - - private JSDynamicObject createFinishDynamicImportCapabilityCallback(JSContext cx, JSRealm realm, JSModuleRecord moduleRecord, boolean onReject) { - JSFunctionData functionData; - if (onReject) { - functionData = cx.getOrCreateBuiltinFunctionData(BuiltinFunctionKey.FinishImportModuleDynamicallyReject, (c) -> createFinishDynamicImportNormalImpl(c, true)); - } else { - functionData = cx.getOrCreateBuiltinFunctionData(BuiltinFunctionKey.FinishImportModuleDynamicallyResolve, (c) -> createFinishDynamicImportNormalImpl(c, false)); - } - JSDynamicObject resolveFunction = JSFunction.create(realm, functionData); - if (setModuleRecord == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - setModuleRecord = insert(PropertySetNode.createSetHidden(CURRENT_MODULE_RECORD_KEY, cx)); - } - setModuleRecord.setValue(resolveFunction, moduleRecord); - return resolveFunction; + callPromiseReject.executeCall(JSArguments.createOneArg(Undefined.instance, moduleLoadedCapability.getReject(), errorObject)); } } - - JavaScriptRootNode root = context.isOptionTopLevelAwait() - ? new TopLevelAwaitImportModuleDynamicallyRootNode(context.getLanguage()) - : new ImportModuleDynamicallyRootNode(context.getLanguage()); - return JSFunctionData.createCallOnly(context, root.getCallTarget(), 0, Strings.EMPTY_STRING); + return JSFunctionData.createCallOnly(context, new LinkAndEvaluateRootNode(context.getLanguage()).getCallTarget(), 0, Strings.EMPTY_STRING); } - private static JSFunctionData createFinishDynamicImportNormalImpl(JSContext cx, boolean onReject) { + private static JSFunctionData createOnFulfilledImpl(JSContext cx) { class FinishDynamicImportNormalRootNode extends JavaScriptRootNode { - @Child private PropertyGetNode getModuleRecord = PropertyGetNode.createGetHidden(CURRENT_MODULE_RECORD_KEY, cx); + @Child private PropertyGetNode getCaptures = PropertyGetNode.createGetHidden(LINK_AND_EVALUATE_KEY, cx); + @Child private JSFunctionCallNode callPromiseResolve = JSFunctionCallNode.createCall(); @Override public Object execute(VirtualFrame frame) { - // ECMA 16.2.1.9 FinishDynamicImport(): reject/resolve `innerPromise`. - // Promise reaction will be handled by the promise registered via `then`. - JSDynamicObject thisFunction = (JSDynamicObject) JSArguments.getFunctionObject(frame.getArguments()); - JSModuleRecord moduleRecord = (JSModuleRecord) getModuleRecord.getValue(thisFunction); - assert moduleRecord != null; - if (onReject) { - assert moduleRecord.getEvaluationError() != null; - throw JSRuntime.rethrow(moduleRecord.getEvaluationError()); - } else { - return cx.getEvaluator().getModuleNamespace(moduleRecord); - } + JSFunctionObject thisFunction = (JSFunctionObject) JSArguments.getFunctionObject(frame.getArguments()); + LinkAndEvaluateArgs captures = (LinkAndEvaluateArgs) getCaptures.getValue(thisFunction); + PromiseCapabilityRecord promiseCapability = captures.promiseCapability; + JSModuleRecord moduleRecord = captures.moduleRecord; + + var namespace = cx.getEvaluator().getModuleNamespace(moduleRecord); + callPromiseResolve.executeCall(JSArguments.createOneArg(Undefined.instance, promiseCapability.getResolve(), namespace)); + return Undefined.instance; } } return JSFunctionData.createCallOnly(cx, new FinishDynamicImportNormalRootNode().getCallTarget(), 0, Strings.EMPTY_STRING); } + private static JSFunctionData createOnRejectedImpl(JSContext cx) { + class RejectDynamicImportRootNode extends JavaScriptRootNode { + @Child protected JavaScriptNode reasonArgument = AccessIndexedArgumentNode.create(0); + @Child private PropertyGetNode getPromiseCapability = PropertyGetNode.createGetHidden(PROMISE_CAPABILITY_KEY, cx); + @Child private JSFunctionCallNode callPromiseReject = JSFunctionCallNode.createCall(); + + @Override + public Object execute(VirtualFrame frame) { + Object reason = reasonArgument.execute(frame); + JSFunctionObject thisFunction = (JSFunctionObject) JSArguments.getFunctionObject(frame.getArguments()); + PromiseCapabilityRecord promiseCapability = (PromiseCapabilityRecord) getPromiseCapability.getValue(thisFunction); + + callPromiseReject.executeCall(JSArguments.createOneArg(Undefined.instance, promiseCapability.getReject(), reason)); + return Undefined.instance; + } + } + return JSFunctionData.createCallOnly(cx, new RejectDynamicImportRootNode().getCallTarget(), 1, Strings.EMPTY_STRING); + } + @Override protected JavaScriptNode copyUninitialized(Set> materializedTags) { if (optionsRefNode == null) { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/PromiseReactionJobNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/PromiseReactionJobNode.java index d8d9173a01c..23116d0e446 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/PromiseReactionJobNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/PromiseReactionJobNode.java @@ -94,7 +94,7 @@ public static PromiseReactionJobNode create(JSContext context) { return new PromiseReactionJobNode(context); } - public JSFunctionObject execute(Object reaction, Object argument) { + public JSFunctionObject execute(PromiseReactionRecord reaction, Object argument) { JSFunctionData functionData = context.getOrCreateBuiltinFunctionData(JSContext.BuiltinFunctionKey.PromiseReactionJob, (c) -> createPromiseReactionJobImpl(c)); JSFunctionObject function = JSFunction.create(getRealm(), functionData); setReaction.setValue(function, reaction); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/TriggerPromiseReactionsNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/TriggerPromiseReactionsNode.java index 2a779d0f220..00f54df83d6 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/TriggerPromiseReactionsNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/TriggerPromiseReactionsNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -43,6 +43,7 @@ import com.oracle.truffle.js.nodes.JavaScriptBaseNode; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.builtins.JSFunctionObject; +import com.oracle.truffle.js.runtime.objects.PromiseReactionRecord; import com.oracle.truffle.js.runtime.objects.Undefined; import com.oracle.truffle.js.runtime.util.SimpleArrayList; @@ -66,7 +67,7 @@ public static TriggerPromiseReactionsNode create(JSContext context) { public Object execute(Object reactions, Object argument) { SimpleArrayList list = (SimpleArrayList) reactions; for (int i = 0; i < list.size(); i++) { - Object reaction = list.get(i); + PromiseReactionRecord reaction = (PromiseReactionRecord) list.get(i); JSFunctionObject job = promiseReactionJob.execute(reaction, argument); context.enqueuePromiseJob(getRealm(), job); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java index 9d95120dbee..508f650a67d 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -54,6 +54,7 @@ import com.oracle.truffle.js.runtime.objects.JSDynamicObject; import com.oracle.truffle.js.runtime.objects.JSModuleData; import com.oracle.truffle.js.runtime.objects.JSModuleRecord; +import com.oracle.truffle.js.runtime.objects.PromiseCapabilityRecord; import com.oracle.truffle.js.runtime.objects.ScriptOrModule; public interface Evaluator { @@ -102,8 +103,12 @@ public interface Evaluator { JSModuleRecord parseJSONModule(JSRealm realm, Source source); + void hostLoadImportedModule(JSRealm realm, ScriptOrModule referrer, Module.ModuleRequest moduleRequest, Object hostDefined, Object payload); + JSModuleRecord hostResolveImportedModule(JSContext context, ScriptOrModule referencingScriptOrModule, Module.ModuleRequest moduleRequest); + PromiseCapabilityRecord loadRequestedModules(JSRealm realm, JSModuleRecord moduleRecord, Object hostDefined); + void moduleLinking(JSRealm realm, JSModuleRecord moduleRecord); Object moduleEvaluation(JSRealm realm, JSModuleRecord moduleRecord); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContext.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContext.java index 9f3e8160924..1d281a858e1 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContext.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContext.java @@ -377,6 +377,10 @@ public enum BuiltinFunctionKey { PromiseValueThunk, PromiseThrower, ImportModuleDynamically, + ContinueDynamicImport, + ContinueDynamicImportLinkAndEvaluateClosure, + ContinueDynamicImportFulfilledClosure, + ContinueDynamicImportRejectedClosure, JavaPackageToPrimitive, RegExpMultiLine, RegExpLastMatch, @@ -400,8 +404,6 @@ public enum BuiltinFunctionKey { TopLevelAwaitResolve, TopLevelAwaitReject, WebAssemblySourceInstantiation, - FinishImportModuleDynamicallyReject, - FinishImportModuleDynamicallyResolve, ExportGetter, OrdinaryWrappedFunctionCall, DecoratorContextAddInitializer, diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java index 6d777ec1f28..37b9348ae1e 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java @@ -249,9 +249,9 @@ private static boolean isModuleType(int moduleType, int expectedType) { } @Override - public JSModuleRecord loadModule(Source source, JSModuleData moduleData) { - String canonicalPath = getCanonicalPath(source); - return moduleMap.computeIfAbsent(canonicalPath, (key) -> new JSModuleRecord(moduleData, this)); + public JSModuleRecord addLoadedModule(ModuleRequest moduleRequest, JSModuleRecord moduleRecord) { + String canonicalPath = getCanonicalPath(moduleRecord.getSource()); + return moduleMap.putIfAbsent(canonicalPath, moduleRecord); } private String getCanonicalPath(Source source) { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleLoader.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleLoader.java index e7610896dcf..1262c3f596a 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleLoader.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,10 +41,12 @@ package com.oracle.truffle.js.runtime.objects; import com.oracle.js.parser.ir.Module.ModuleRequest; -import com.oracle.truffle.api.source.Source; public interface JSModuleLoader { JSModuleRecord resolveImportedModule(ScriptOrModule referencingModule, ModuleRequest moduleRequest); - JSModuleRecord loadModule(Source moduleSource, JSModuleData moduleData); + @SuppressWarnings("unused") + default JSModuleRecord addLoadedModule(ModuleRequest moduleRequest, JSModuleRecord moduleRecord) { + throw new UnsupportedOperationException(); + } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java index eb591f1d62e..5e557c8d90c 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java @@ -43,11 +43,15 @@ import java.util.ArrayList; import java.util.List; +import org.graalvm.collections.EconomicMap; + +import com.oracle.js.parser.ir.Module.ModuleRequest; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.strings.TruffleString; +import com.oracle.truffle.js.runtime.JSRealm; import com.oracle.truffle.js.runtime.JSRuntime; import com.oracle.truffle.js.runtime.Strings; import com.oracle.truffle.js.runtime.builtins.JSFunctionData; @@ -59,6 +63,7 @@ public class JSModuleRecord extends ScriptOrModule { public enum Status { + New, Unlinked, Linking, Linked, @@ -93,22 +98,23 @@ public enum Status { * "evaluating", this non-negative number records the point at which the module was first * visited during the ongoing depth-first traversal of the dependency graph. */ - private int dfsIndex; + private int dfsIndex = -1; /** * Auxiliary field used during Link and Evaluate only. If [[Status]] is "linking" or * "evaluating", this is either the module's own [[DFSIndex]] or that of an "earlier" module in * the same strongly connected component. */ - private int dfsAncestorIndex; + private int dfsAncestorIndex = -1; + + private EconomicMap loadedModules = EconomicMap.create(); - @SuppressWarnings("this-escape") public JSModuleRecord(JSModuleData parsedModule, JSModuleLoader moduleLoader) { super(parsedModule.getContext(), parsedModule.getSource()); this.parsedModule = parsedModule; this.moduleLoader = moduleLoader; this.hasTLA = parsedModule.isTopLevelAsync(); this.hostDefined = null; - setUnlinked(); + this.status = Status.New; } public JSModuleRecord(JSModuleData moduleData, JSModuleLoader moduleLoader, Object hostDefined) { @@ -325,6 +331,24 @@ public JSModuleRecord getCycleRoot() { return cycleRoot; } + @TruffleBoundary + @Override + public JSModuleRecord getLoadedModule(JSRealm realm, ModuleRequest moduleRequest) { + return loadedModules.get(moduleRequest); + } + + @TruffleBoundary + @Override + public JSModuleRecord addLoadedModule(JSRealm realm, ModuleRequest moduleRequest, JSModuleRecord module) { + return loadedModules.putIfAbsent(moduleRequest, module); + } + + @TruffleBoundary + public JSModuleRecord getImportedModule(ModuleRequest moduleRequest) { + assert loadedModules.containsKey(moduleRequest) : moduleRequest; + return loadedModules.get(moduleRequest); + } + @Override public void rememberImportedModuleSource(TruffleString moduleSpecifier, Source moduleSource) { parsedModule.rememberImportedModuleSource(moduleSpecifier, moduleSource); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/ScriptOrModule.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/ScriptOrModule.java index ff53e261e4e..4d3afd6288e 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/ScriptOrModule.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/ScriptOrModule.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -45,10 +45,13 @@ import java.util.Map; import java.util.concurrent.ConcurrentHashMap; +import com.oracle.js.parser.ir.Module.ModuleRequest; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.runtime.JSContext; +import com.oracle.truffle.js.runtime.JSRealm; /** * Script or Module Record. @@ -76,6 +79,16 @@ public final Source getSource() { return source; } + @TruffleBoundary + public JSModuleRecord getLoadedModule(JSRealm realm, ModuleRequest moduleRequest) { + return realm.getModuleLoader().resolveImportedModule(this, moduleRequest); + } + + @TruffleBoundary + public JSModuleRecord addLoadedModule(JSRealm realm, ModuleRequest moduleRequest, JSModuleRecord moduleRecord) { + return realm.getModuleLoader().addLoadedModule(moduleRequest, moduleRecord); + } + /** * Keep a link from the referencing module or script to the imported module's {@link Source}, so * that the latter is kept alive for the lifetime of the former. diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java index a80b86b64f8..274f2158c40 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java @@ -2726,7 +2726,7 @@ private WeakCallback updateWeakCallback(Object object, long reference, long data target = jsObject; key = HIDDEN_WEAK_CALLBACK; } else if (object instanceof JSModuleRecord moduleRecord) { - if (moduleRecord.getStatus() == JSModuleRecord.Status.Unlinked) { + if (moduleRecord.getStatus() == JSModuleRecord.Status.New || moduleRecord.getStatus() == JSModuleRecord.Status.Unlinked) { assert (callbackPointer == 0); // ClearWeak() called on a module that cannot be weak yet return null; @@ -3798,17 +3798,19 @@ public Object moduleCompile(Object context, Object sourceCode, Object name, Obje // Get the correct Source instance to be used as weak map key. source = parsedModule.getSource(); hostDefinedOptionsMap.put(source, hostDefinedOptions); - JSModuleRecord moduleRecord = new JSModuleRecord(parsedModule, getModuleLoader()); + JSModuleRecord moduleRecord = new JSModuleRecord(parsedModule, getModuleLoader(), hostDefinedOptions); return moduleRecord; } public void moduleInstantiate(Object context, Object module, long resolveCallback) { JSRealm jsRealm = (JSRealm) context; + JSModuleRecord moduleRecord = (JSModuleRecord) module; JSContext jsContext = jsRealm.getContext(); ESModuleLoader loader = getModuleLoader(); loader.setResolver(resolveCallback); try { - jsContext.getEvaluator().moduleLinking(jsRealm, (JSModuleRecord) module); + jsContext.getEvaluator().loadRequestedModules(jsRealm, moduleRecord, moduleRecord.getHostDefined()); + jsContext.getEvaluator().moduleLinking(jsRealm, moduleRecord); } finally { loader.setResolver(0); } @@ -3840,6 +3842,7 @@ public Object moduleEvaluate(Object context, Object module) { public int moduleGetStatus(Object module) { JSModuleRecord record = (JSModuleRecord) module; switch (record.getStatus()) { + case New: case Unlinked: return 0; // v8::Module::Status::kUninstantiated case Linking: @@ -3850,13 +3853,13 @@ public int moduleGetStatus(Object module) { return 3; // v8::Module::Status::Evaluating case EvaluatingAsync: case Evaluated: - default: - assert (record.getStatus() == JSModuleRecord.Status.Evaluated || record.getStatus() == JSModuleRecord.Status.EvaluatingAsync); if (record.getEvaluationError() == null) { return 4; // v8::Module::Status::kEvaluated } else { return 5; // v8::Module::Status::kErrored } + default: + throw Errors.shouldNotReachHereUnexpectedValue(record.getStatus()); } } @@ -4270,11 +4273,6 @@ public JSModuleRecord resolveImportedModule(ScriptOrModule referrer, ModuleReque referrerCache.put(specifier, result); return result; } - - @Override - public JSModuleRecord loadModule(Source moduleSource, JSModuleData moduleData) { - throw new UnsupportedOperationException(); - } } /** From f9db4ab873a90d5470f85c2037a74aaf4945dd97 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Fri, 9 Aug 2024 14:26:59 +0200 Subject: [PATCH 184/265] Use GetImportedModule instead of HostResolveImportedModule. --- .../truffle/js/parser/GraalJSEvaluator.java | 28 ++++++++----------- .../oracle/truffle/js/runtime/Evaluator.java | 2 -- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java index 28c62839f3b..bda7fa3e48d 100644 --- a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java +++ b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java @@ -459,14 +459,9 @@ private void setSyntheticModuleExport(JSModuleRecord module) { } @TruffleBoundary - @Override - public JSModuleRecord hostResolveImportedModule(JSContext context, ScriptOrModule referrer, ModuleRequest moduleRequest) { - JSModuleLoader moduleLoader = referrer instanceof JSModuleRecord ? ((JSModuleRecord) referrer).getModuleLoader() : JSRealm.get(null).getModuleLoader(); - return moduleLoader.resolveImportedModule(referrer, filterSupportedImportAttributes(context, moduleRequest)); - } - - private static JSModuleRecord hostResolveImportedModule(JSModuleRecord referencingModule, ModuleRequest moduleRequest) { - return referencingModule.getModuleLoader().resolveImportedModule(referencingModule, filterSupportedImportAttributes(referencingModule.getContext(), moduleRequest)); + private static JSModuleRecord hostResolveImportedModule(JSRealm realm, ScriptOrModule referrer, ModuleRequest moduleRequest) { + JSModuleLoader moduleLoader = referrer instanceof JSModuleRecord ? ((JSModuleRecord) referrer).getModuleLoader() : realm.getModuleLoader(); + return moduleLoader.resolveImportedModule(referrer, filterSupportedImportAttributes(realm.getContext(), moduleRequest)); } private static ModuleRequest filterSupportedImportAttributes(JSContext context, ModuleRequest moduleRequest) { @@ -505,7 +500,7 @@ private Collection getExportedNames(JSModuleRecord moduleRecord, exportedNames.add(exportEntry.getExportName()); } for (ExportEntry exportEntry : module.getStarExportEntries()) { - JSModuleRecord requestedModule = hostResolveImportedModule(moduleRecord, exportEntry.getModuleRequest()); + JSModuleRecord requestedModule = moduleRecord.getImportedModule(exportEntry.getModuleRequest()); Collection starNames = getExportedNames(requestedModule, exportStarSet); for (TruffleString starName : starNames) { if (!starName.equals(Module.DEFAULT_NAME)) { @@ -554,7 +549,7 @@ private ExportResolution resolveExport(JSModuleRecord referencingModule, Truffle } for (ExportEntry exportEntry : module.getIndirectExportEntries()) { if (exportEntry.getExportName().equals(exportName)) { - JSModuleRecord importedModule = hostResolveImportedModule(referencingModule, exportEntry.getModuleRequest()); + JSModuleRecord importedModule = referencingModule.getImportedModule(exportEntry.getModuleRequest()); if (exportEntry.getImportName().equals(Module.STAR_NAME)) { // Assert: module does not provide the direct binding for this export. return ExportResolution.resolved(importedModule, Module.NAMESPACE_EXPORT_BINDING_NAME); @@ -571,7 +566,7 @@ private ExportResolution resolveExport(JSModuleRecord referencingModule, Truffle } ExportResolution starResolution = ExportResolution.notFound(); for (ExportEntry exportEntry : module.getStarExportEntries()) { - JSModuleRecord importedModule = hostResolveImportedModule(referencingModule, exportEntry.getModuleRequest()); + JSModuleRecord importedModule = referencingModule.getImportedModule(exportEntry.getModuleRequest()); ExportResolution resolution = resolveExport(importedModule, exportName, resolveSet); if (resolution.isAmbiguous()) { return resolution; @@ -680,11 +675,12 @@ private void innerModuleLoading(JSRealm realm, GraphLoadingState state, JSModule * result), where result is either a normal completion containing the loaded Module Record or a * throw completion, either synchronously or asynchronously. */ + @TruffleBoundary @Override public void hostLoadImportedModule(JSRealm realm, ScriptOrModule referrer, ModuleRequest moduleRequest, Object hostDefined, Object payload) { Completion moduleCompletion; try { - JSModuleRecord module = hostResolveImportedModule(realm.getContext(), referrer, moduleRequest); + JSModuleRecord module = hostResolveImportedModule(realm, referrer, moduleRequest); moduleCompletion = Completion.forNormal(module); } catch (AbstractTruffleException e) { moduleCompletion = Completion.forThrow(getErrorObject(e)); @@ -773,8 +769,8 @@ private int innerModuleLinking(JSRealm realm, JSModuleRecord moduleRecord, Deque stack.push(moduleRecord); Module module = moduleRecord.getModule(); - for (ModuleRequest requestedModule : module.getRequestedModules()) { - JSModuleRecord requiredModule = hostResolveImportedModule(moduleRecord, requestedModule); + for (ModuleRequest required : module.getRequestedModules()) { + JSModuleRecord requiredModule = moduleRecord.getImportedModule(required); index = innerModuleLinking(realm, requiredModule, stack, index); assert requiredModule.getStatus() == Status.Linking || requiredModule.getStatus() == Status.Linked || requiredModule.getStatus() == Status.EvaluatingAsync || requiredModule.getStatus() == Status.Evaluated : requiredModule.getStatus(); @@ -908,8 +904,8 @@ private int innerModuleEvaluation(JSRealm realm, JSModuleRecord moduleRecord, De stack.push(moduleRecord); Module module = moduleRecord.getModule(); - for (ModuleRequest requestedModule : module.getRequestedModules()) { - JSModuleRecord requiredModule = hostResolveImportedModule(moduleRecord, requestedModule); + for (ModuleRequest required : module.getRequestedModules()) { + JSModuleRecord requiredModule = moduleRecord.getImportedModule(required); // Note: Link must have completed successfully prior to invoking this method, // so every requested module is guaranteed to resolve successfully. index = innerModuleEvaluation(realm, requiredModule, stack, index); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java index 508f650a67d..eecc6d1103f 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java @@ -105,8 +105,6 @@ public interface Evaluator { void hostLoadImportedModule(JSRealm realm, ScriptOrModule referrer, Module.ModuleRequest moduleRequest, Object hostDefined, Object payload); - JSModuleRecord hostResolveImportedModule(JSContext context, ScriptOrModule referencingScriptOrModule, Module.ModuleRequest moduleRequest); - PromiseCapabilityRecord loadRequestedModules(JSRealm realm, JSModuleRecord moduleRecord, Object hostDefined); void moduleLinking(JSRealm realm, JSModuleRecord moduleRecord); From 2edd24f337fcef919d015ef57f1464800bd182c6 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 14 Aug 2024 17:43:38 +0200 Subject: [PATCH 185/265] Module.Evaluate() should return rejected promise, not throw. --- .../oracle/truffle/js/parser/GraalJSEvaluator.java | 1 - .../oracle/truffle/trufflenode/GraalJSAccess.java | 12 +++--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java index bda7fa3e48d..1056269c47b 100644 --- a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java +++ b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java @@ -840,7 +840,6 @@ public Object moduleEvaluation(JSRealm realm, JSModuleRecord moduleRecord) { assert stack.isEmpty(); } catch (AbstractTruffleException e) { handleModuleEvaluationError(module, stack, e); - throw e; } return capability.getPromise(); } else { diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java index 274f2158c40..0327dd948ba 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java @@ -3825,17 +3825,11 @@ public Object moduleEvaluate(Object context, Object module) { jsContext.getEvaluator().moduleEvaluation(jsRealm, moduleRecord); } - if (!moduleRecord.hasTLA()) { - Throwable evaluationError = moduleRecord.getEvaluationError(); - if (evaluationError != null) { - throw JSRuntime.rethrow(evaluationError); - } - } PromiseCapabilityRecord promiseCapability = moduleRecord.getTopLevelCapability(); - if (promiseCapability == null) { - return moduleRecord.getExecutionResult(); - } else { + if (promiseCapability != null) { return promiseCapability.getPromise(); + } else { + return moduleRecord.getExecutionResultOrThrow(); } } From 3dd3686c7ad289851a9799ee8cdd762ba5406959 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Fri, 9 Aug 2024 19:18:37 +0200 Subject: [PATCH 186/265] Push import call site as EncapsulatingNodeReference. --- .../truffle/js/nodes/promise/ImportCallNode.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java index d75a4932b00..0c59c1da4a3 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java @@ -50,6 +50,8 @@ import com.oracle.truffle.api.exception.AbstractTruffleException; import com.oracle.truffle.api.frame.VirtualFrame; import com.oracle.truffle.api.instrumentation.Tag; +import com.oracle.truffle.api.nodes.EncapsulatingNodeReference; +import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.object.HiddenKey; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.lang.JavaScriptLanguage; @@ -153,7 +155,7 @@ private Object executeWithoutAttributes(ScriptOrModule referencingScriptOrModule } catch (AbstractTruffleException ex) { return rejectPromise(promiseCapability, ex); } - return hostImportModuleDynamically(referencingScriptOrModule, ModuleRequest.create(specifierString), promiseCapability); + return hostImportModuleDynamicallyWithSite(referencingScriptOrModule, ModuleRequest.create(specifierString), promiseCapability); } @SuppressWarnings("unchecked") @@ -225,7 +227,17 @@ private Object executeAttributes(VirtualFrame frame, ScriptOrModule referencingS } } ModuleRequest moduleRequest = attributes == null ? ModuleRequest.create(specifierString) : createModuleRequestWithAttributes(specifierString, attributes); - return hostImportModuleDynamically(referencingScriptOrModule, moduleRequest, promiseCapability); + return hostImportModuleDynamicallyWithSite(referencingScriptOrModule, moduleRequest, promiseCapability); + } + + private JSDynamicObject hostImportModuleDynamicallyWithSite(ScriptOrModule referrer, ModuleRequest moduleRequest, PromiseCapabilityRecord promiseCapability) { + EncapsulatingNodeReference current = EncapsulatingNodeReference.getCurrent(); + Node prev = current.set(this); + try { + return hostImportModuleDynamically(referrer, moduleRequest, promiseCapability); + } finally { + current.set(prev); + } } @TruffleBoundary From 843cb24472be2f98a00fd7a9db26a85d0c9040f4 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Fri, 9 Aug 2024 18:49:56 +0200 Subject: [PATCH 187/265] Fix test for async stack trace from dynamic import. --- .../js/test/ModuleNotFoundErrorTest.java | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/ModuleNotFoundErrorTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/ModuleNotFoundErrorTest.java index f4ee5479100..f8c3a140277 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/ModuleNotFoundErrorTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/ModuleNotFoundErrorTest.java @@ -140,7 +140,7 @@ public void testModuleNotFoundErrorFromDynamicImport() { public void testAsyncStackTraceOfModuleNotFoundErrorFromDynamicImport() { String mainCode = """ async function caller() { - await import("./not-found.mjs"); + await Promise.resolve().then(() => import("./not-found.mjs")); } try { await caller(); @@ -163,4 +163,30 @@ async function caller() { } } + @Test + public void testSyncStackTraceOfModuleNotFoundErrorFromDynamicImport() { + String mainCode = """ + async function caller() { + await import("./not-found.mjs"); + } + try { + await caller(); + } catch (e) { + console.log(e.stack); + } + """; + Source fileSource = Source.newBuilder(JavaScriptLanguage.ID, new File("main.mjs")).content(mainCode).buildLiteral(); + Source literalSource = Source.newBuilder(JavaScriptLanguage.ID, mainCode, "main.mjs").buildLiteral(); + for (Source mainSource : List.of(fileSource, literalSource)) { + ByteArrayOutputStream outs = new ByteArrayOutputStream(); + try (Context context = JSTest.newContextBuilder().out(outs).allowIO(IOAccess.newBuilder().allowHostFileAccess(true).build()).build()) { + context.eval(mainSource); + + String output = outs.toString(StandardCharsets.UTF_8); + assertThat(output, allOf(containsString("Cannot find module"), containsString("not-found.mjs"))); + assertThat(output, allOf(containsString("imported from"), containsString("main.mjs"))); + assertThat(output, allOf(containsString("at caller"), containsString("main.mjs:2"))); + } + } + } } From b87635e007b171b9cb3db173edd0b6d98819f11f Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 16 Aug 2024 21:31:29 +0000 Subject: [PATCH 188/265] Update graal import. --- graal-js/mx.graal-js/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/mx.graal-js/suite.py b/graal-js/mx.graal-js/suite.py index 08213fe6a29..d852c9c0830 100644 --- a/graal-js/mx.graal-js/suite.py +++ b/graal-js/mx.graal-js/suite.py @@ -24,7 +24,7 @@ { "name" : "regex", "subdir" : True, - "version" : "a55537477744db396e66e321edca77ab26dbaa9c", + "version" : "3d2b94bd699c4c8ece2061d54f9f99f8ab8b6099", "urls" : [ {"url" : "https://github.com/oracle/graal.git", "kind" : "git"}, ] From c0680efb6da7846c26c6e883d1af7eb22b998879 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Mon, 19 Aug 2024 14:03:32 +0200 Subject: [PATCH 189/265] Try to avoid non-zero index offset when going from empty to contiguous array. --- .../array/dyn/AbstractConstantEmptyArray.java | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractConstantEmptyArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractConstantEmptyArray.java index c08abcfcba0..4587edccd19 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractConstantEmptyArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractConstantEmptyArray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -116,11 +116,12 @@ public long previousElementIndex(JSDynamicObject object, long index) { public AbstractIntArray createWriteableInt(JSDynamicObject object, long index, int value, Node node, CreateWritableProfileAccess profile) { assert index >= 0; // corner case, length would not be int then int capacity = lengthInt(object); - int[] initialArray = new int[calcNewArraySize(capacity, node, profile)]; AbstractIntArray newArray; if (profile.indexZero(node, index == 0)) { + int[] initialArray = new int[calcNewArraySize(capacity, node, profile)]; newArray = ZeroBasedIntArray.makeZeroBasedIntArray(object, capacity, 0, initialArray, integrityLevel); } else { + int[] initialArray = new int[calcNewArraySize(capacity, index, node, profile)]; newArray = createWritableIntContiguous(object, capacity, index, initialArray, node, profile); } if (JSConfig.TraceArrayTransitions) { @@ -151,14 +152,24 @@ private static int calcNewArraySize(int capacity, Node node, CreateWritableProfi } } + private static int calcNewArraySize(int capacity, long index, Node node, CreateWritableProfileAccess profile) { + long length = Math.max(Math.max(capacity, index + 1), JSConfig.InitialArraySize); + if (profile.newArrayLengthBelowLimit(node, length < JSConfig.MaxFlatArraySize)) { + return (int) length; + } else { + return JSConfig.InitialArraySize; + } + } + @Override public AbstractDoubleArray createWriteableDouble(JSDynamicObject object, long index, double value, Node node, CreateWritableProfileAccess profile) { int capacity = lengthInt(object); - double[] initialArray = new double[calcNewArraySize(capacity, node, profile)]; AbstractDoubleArray newArray; if (profile.indexZero(node, index == 0)) { + double[] initialArray = new double[calcNewArraySize(capacity, node, profile)]; newArray = ZeroBasedDoubleArray.makeZeroBasedDoubleArray(object, capacity, 0, initialArray, integrityLevel); } else { + double[] initialArray = new double[calcNewArraySize(capacity, index, node, profile)]; newArray = createWritableDoubleContiguous(object, capacity, index, initialArray, node, profile); } if (JSConfig.TraceArrayTransitions) { @@ -182,11 +193,12 @@ private AbstractDoubleArray createWritableDoubleContiguous(JSDynamicObject objec @Override public AbstractJSObjectArray createWriteableJSObject(JSDynamicObject object, long index, JSDynamicObject value, Node node, CreateWritableProfileAccess profile) { int capacity = lengthInt(object); - JSDynamicObject[] initialArray = new JSDynamicObject[calcNewArraySize(capacity, node, profile)]; AbstractJSObjectArray newArray; if (profile.indexZero(node, index == 0)) { + JSDynamicObject[] initialArray = new JSDynamicObject[calcNewArraySize(capacity, node, profile)]; newArray = ZeroBasedJSObjectArray.makeZeroBasedJSObjectArray(object, capacity, 0, initialArray, integrityLevel); } else { + JSDynamicObject[] initialArray = new JSDynamicObject[calcNewArraySize(capacity, index, node, profile)]; newArray = createWritableJSObjectContiguous(object, capacity, index, initialArray, node, profile); } if (JSConfig.TraceArrayTransitions) { @@ -210,11 +222,12 @@ private AbstractJSObjectArray createWritableJSObjectContiguous(JSDynamicObject o @Override public AbstractObjectArray createWriteableObject(JSDynamicObject object, long index, Object value, Node node, CreateWritableProfileAccess profile) { int capacity = lengthInt(object); - Object[] initialArray = new Object[calcNewArraySize(capacity, node, profile)]; AbstractObjectArray newArray; if (profile.indexZero(node, index == 0)) { + Object[] initialArray = new Object[calcNewArraySize(capacity, node, profile)]; newArray = ZeroBasedObjectArray.makeZeroBasedObjectArray(object, capacity, 0, initialArray, integrityLevel); } else { + Object[] initialArray = new Object[calcNewArraySize(capacity, index, node, profile)]; newArray = createWritableObjectContiguous(object, capacity, index, initialArray, node, profile); } if (JSConfig.TraceArrayTransitions) { From 2cf26ec98982051ac8d830509f6c6029bdcacf6f Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Mon, 19 Aug 2024 17:39:03 +0200 Subject: [PATCH 190/265] nextElementIndexHoles should return MAX_SAFE_INTEGER_LONG for an empty array. --- .../truffle/js/runtime/array/dyn/AbstractWritableArray.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractWritableArray.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractWritableArray.java index e0f15f04bae..04d575c3eb5 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractWritableArray.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/array/dyn/AbstractWritableArray.java @@ -429,10 +429,10 @@ public long nextElementIndex(JSDynamicObject object, long index) { protected final long nextElementIndexHoles(JSDynamicObject object, long index0) { long index = index0; long firstIdx = firstElementIndex(object); + long lastI = lastElementIndex(object); if (index0 < firstIdx) { - return firstIdx; + return (firstIdx <= lastI) ? firstIdx : JSRuntime.MAX_SAFE_INTEGER_LONG; } - long lastI = lastElementIndex(object); do { index++; if (index > lastI) { From 905e725775d44afa26ec0e2d28c63fcbd4056644 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Tue, 20 Aug 2024 13:33:37 +0200 Subject: [PATCH 191/265] Updating DynamicArrayTest.testInBoundsContiguousAccess() test. --- .../com/oracle/truffle/js/test/runtime/DynamicArrayTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/runtime/DynamicArrayTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/runtime/DynamicArrayTest.java index e3b1f953eca..eb4956d0299 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/runtime/DynamicArrayTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/runtime/DynamicArrayTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -110,7 +110,7 @@ public void testInBoundsContiguousAccess() { assertEquals(true, array.isInBoundsFast(arrayObject, 3)); assertEquals(true, array.isInBounds(arrayObject, 2)); assertEquals(false, array.isInBoundsFast(arrayObject, 2)); - assertEquals(false, array.isInBounds(arrayObject, 4)); + assertEquals(true, array.isInBounds(arrayObject, 4)); assertEquals(false, array.isInBoundsFast(arrayObject, 4)); array.setInBounds(arrayObject, 2, INT, null, SetSupportedProfileAccess.getUncached()); From 084439e692d01ad677d442702e91f662400b7a3a Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 23 Aug 2024 21:20:56 +0000 Subject: [PATCH 192/265] Update graal import. --- graal-js/mx.graal-js/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/mx.graal-js/suite.py b/graal-js/mx.graal-js/suite.py index d852c9c0830..22e2fd84f52 100644 --- a/graal-js/mx.graal-js/suite.py +++ b/graal-js/mx.graal-js/suite.py @@ -24,7 +24,7 @@ { "name" : "regex", "subdir" : True, - "version" : "3d2b94bd699c4c8ece2061d54f9f99f8ab8b6099", + "version" : "7227e7620849054055835c6719acba43d48e36c4", "urls" : [ {"url" : "https://github.com/oracle/graal.git", "kind" : "git"}, ] From 48ea6ce0f3904f1414c7bbfd2173c28bf0babded Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 23 Aug 2024 21:20:57 +0000 Subject: [PATCH 193/265] Sync CI files. --- common.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/common.json b/common.json index 7aa08491fe3..1e47cd9bdfd 100644 --- a/common.json +++ b/common.json @@ -45,13 +45,13 @@ "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.2+13-jvmci-23.1-b33-sulong", "platformspecific": true }, "graalvm-ee-21": {"name": "graalvm-java21", "version": "23.1.3", "platformspecific": true }, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+10", "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+10-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+10-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+10-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+10-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+10-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+10-jvmci-b01-sulong", "platformspecific": true } + "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+11", "platformspecific": true, "extrabundles": ["static-libs"]}, + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+11-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+11-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+11-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+11-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+11-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+11-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { From 0d604ad2d65eb3856126ea383bc1ffe77c40c789 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 12 Aug 2024 18:59:04 +0200 Subject: [PATCH 194/265] Refactoring: Introduce AbstractModuleRecord and move getModuleNamespace and resolveExport to instance methods. --- .../truffle/js/parser/GraalJSEvaluator.java | 169 ++--------------- .../truffle/js/builtins/DebugBuiltins.java | 9 +- .../commonjs/NpmCompatibleESModuleLoader.java | 11 +- .../nodes/module/ReadImportBindingNode.java | 9 +- .../nodes/module/ResolveNamedImportNode.java | 8 +- .../nodes/module/ResolveStarImportNode.java | 4 +- .../js/nodes/promise/ImportCallNode.java | 10 +- .../oracle/truffle/js/runtime/Evaluator.java | 6 - .../runtime/builtins/JSModuleNamespace.java | 2 +- .../runtime/objects/AbstractModuleRecord.java | 87 +++++++++ .../objects/DefaultESModuleLoader.java | 10 +- .../js/runtime/objects/JSModuleLoader.java | 4 +- .../js/runtime/objects/JSModuleRecord.java | 172 ++++++++++++++++-- .../js/runtime/objects/ScriptOrModule.java | 4 +- .../truffle/trufflenode/GraalJSAccess.java | 14 +- 15 files changed, 304 insertions(+), 215 deletions(-) create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/AbstractModuleRecord.java diff --git a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java index 1056269c47b..f6ed188ed65 100644 --- a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java +++ b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java @@ -45,7 +45,6 @@ import java.nio.ByteBuffer; import java.util.ArrayDeque; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; @@ -112,10 +111,9 @@ import com.oracle.truffle.js.runtime.builtins.JSFunction; import com.oracle.truffle.js.runtime.builtins.JSFunctionData; import com.oracle.truffle.js.runtime.builtins.JSFunctionObject; -import com.oracle.truffle.js.runtime.builtins.JSModuleNamespace; -import com.oracle.truffle.js.runtime.builtins.JSModuleNamespaceObject; import com.oracle.truffle.js.runtime.builtins.JSPromise; import com.oracle.truffle.js.runtime.builtins.JSPromiseObject; +import com.oracle.truffle.js.runtime.objects.AbstractModuleRecord; import com.oracle.truffle.js.runtime.objects.Completion; import com.oracle.truffle.js.runtime.objects.ExportResolution; import com.oracle.truffle.js.runtime.objects.JSDynamicObject; @@ -128,7 +126,6 @@ import com.oracle.truffle.js.runtime.objects.PromiseCapabilityRecord; import com.oracle.truffle.js.runtime.objects.ScriptOrModule; import com.oracle.truffle.js.runtime.objects.Undefined; -import com.oracle.truffle.js.runtime.util.Pair; /** * This is the main external entry into the GraalJS parser. @@ -296,15 +293,15 @@ private Object evalModule(JSRealm realm) { ModuleRequest moduleRequest = ModuleRequest.create(Strings.fromJavaString(source.getName())); realm.getModuleLoader().addLoadedModule(moduleRequest, moduleRecord); - JSPromiseObject loadPromise = (JSPromiseObject) loadRequestedModules(realm, moduleRecord, Undefined.instance).getPromise(); + JSPromiseObject loadPromise = (JSPromiseObject) moduleRecord.loadRequestedModules(realm, Undefined.instance).getPromise(); assert !JSPromise.isPending(loadPromise); // If loading failed, we must not perform module linking. if (JSPromise.isRejected(loadPromise)) { throw JSRuntime.getException(loadPromise.getPromiseResult(), this); } - moduleLinking(realm, moduleRecord); - Object promise = moduleEvaluation(realm, moduleRecord); + moduleRecord.link(realm); + Object promise = moduleRecord.evaluate(realm); boolean isAsync = context.isOptionTopLevelAwait() && moduleRecord.isAsyncEvaluation(); if (isAsync) { JSFunctionObject onRejected = createTopLevelAwaitReject(context, realm); @@ -313,7 +310,7 @@ private Object evalModule(JSRealm realm) { performPromiseThenNode.execute((JSPromiseObject) promise, onAccepted, onRejected, null); } if (context.getLanguageOptions().esmEvalReturnsExports()) { - JSDynamicObject moduleNamespace = getModuleNamespace(moduleRecord); + JSDynamicObject moduleNamespace = moduleRecord.getModuleNamespace(); assert moduleNamespace != null; return moduleNamespace; } else if (isAsync) { @@ -459,7 +456,7 @@ private void setSyntheticModuleExport(JSModuleRecord module) { } @TruffleBoundary - private static JSModuleRecord hostResolveImportedModule(JSRealm realm, ScriptOrModule referrer, ModuleRequest moduleRequest) { + private static AbstractModuleRecord hostResolveImportedModule(JSRealm realm, ScriptOrModule referrer, ModuleRequest moduleRequest) { JSModuleLoader moduleLoader = referrer instanceof JSModuleRecord ? ((JSModuleRecord) referrer).getModuleLoader() : realm.getModuleLoader(); return moduleLoader.resolveImportedModule(referrer, filterSupportedImportAttributes(realm.getContext(), moduleRequest)); } @@ -479,135 +476,6 @@ private static ModuleRequest filterSupportedImportAttributes(JSContext context, return moduleRequest.withAttributes(supportedAttributes); } - Collection getExportedNames(JSModuleRecord moduleRecord) { - return getExportedNames(moduleRecord, new HashSet<>()); - } - - private Collection getExportedNames(JSModuleRecord moduleRecord, Set exportStarSet) { - if (exportStarSet.contains(moduleRecord)) { - // Assert: We've reached the starting point of an import * circularity. - return Collections.emptySortedSet(); - } - exportStarSet.add(moduleRecord); - Collection exportedNames = new HashSet<>(); - Module module = moduleRecord.getModule(); - for (ExportEntry exportEntry : module.getLocalExportEntries()) { - // Assert: module provides the direct binding for this export. - exportedNames.add(exportEntry.getExportName()); - } - for (ExportEntry exportEntry : module.getIndirectExportEntries()) { - // Assert: module imports a specific binding for this export. - exportedNames.add(exportEntry.getExportName()); - } - for (ExportEntry exportEntry : module.getStarExportEntries()) { - JSModuleRecord requestedModule = moduleRecord.getImportedModule(exportEntry.getModuleRequest()); - Collection starNames = getExportedNames(requestedModule, exportStarSet); - for (TruffleString starName : starNames) { - if (!starName.equals(Module.DEFAULT_NAME)) { - if (!exportedNames.contains(starName)) { - exportedNames.add(starName); - } - } - } - } - return exportedNames; - } - - @TruffleBoundary - @Override - public ExportResolution resolveExport(JSModuleRecord referencingModule, TruffleString exportName) { - return resolveExport(referencingModule, exportName, new HashSet<>()); - } - - /** - * ResolveExport attempts to resolve an imported binding to the actual defining module and local - * binding name. The defining module may be the module represented by the Module Record this - * method was invoked on or some other module that is imported by that module. The parameter - * resolveSet is use to detect unresolved circular import/export paths. If a pair consisting of - * specific Module Record and exportName is reached that is already in resolveSet, an import - * circularity has been encountered. Before recursively calling ResolveExport, a pair consisting - * of module and exportName is added to resolveSet. - * - * If a defining module is found a Record {[[module]], [[bindingName]]} is returned. This record - * identifies the resolved binding of the originally requested export. If no definition was - * found or the request is found to be circular, null is returned. If the request is found to be - * ambiguous, the string "ambiguous" is returned. - */ - private ExportResolution resolveExport(JSModuleRecord referencingModule, TruffleString exportName, Set> resolveSet) { - Pair resolved = new Pair<>(referencingModule, exportName); - if (resolveSet.contains(resolved)) { - // Assert: this is a circular import request. - return ExportResolution.notFound(); - } - resolveSet.add(resolved); - Module module = referencingModule.getModule(); - for (ExportEntry exportEntry : module.getLocalExportEntries()) { - if (exportEntry.getExportName().equals(exportName)) { - // Assert: module provides the direct binding for this export. - return ExportResolution.resolved(referencingModule, exportEntry.getLocalName()); - } - } - for (ExportEntry exportEntry : module.getIndirectExportEntries()) { - if (exportEntry.getExportName().equals(exportName)) { - JSModuleRecord importedModule = referencingModule.getImportedModule(exportEntry.getModuleRequest()); - if (exportEntry.getImportName().equals(Module.STAR_NAME)) { - // Assert: module does not provide the direct binding for this export. - return ExportResolution.resolved(importedModule, Module.NAMESPACE_EXPORT_BINDING_NAME); - } else { - // Assert: module imports a specific binding for this export. - return resolveExport(importedModule, exportEntry.getImportName(), resolveSet); - } - } - } - if (exportName.equals(Module.DEFAULT_NAME)) { - // Assert: A default export was not explicitly defined by this module. - return ExportResolution.notFound(); - // NOTE: A default export cannot be provided by an `export *` or `export * from "mod"`. - } - ExportResolution starResolution = ExportResolution.notFound(); - for (ExportEntry exportEntry : module.getStarExportEntries()) { - JSModuleRecord importedModule = referencingModule.getImportedModule(exportEntry.getModuleRequest()); - ExportResolution resolution = resolveExport(importedModule, exportName, resolveSet); - if (resolution.isAmbiguous()) { - return resolution; - } - if (!resolution.isNull()) { - if (starResolution.isNull()) { - starResolution = resolution; - } else { - // Assert: there is more than one * import that includes the requested name. - if (!resolution.equals(starResolution)) { - return ExportResolution.ambiguous(); - } - } - } - } - return starResolution; - } - - @TruffleBoundary - @Override - public JSDynamicObject getModuleNamespace(JSModuleRecord moduleRecord) { - if (moduleRecord.getNamespace() != null) { - return moduleRecord.getNamespace(); - } - - Collection exportedNames = getExportedNames(moduleRecord); - List> unambiguousNames = new ArrayList<>(); - for (TruffleString exportedName : exportedNames) { - ExportResolution resolution = resolveExport(moduleRecord, exportedName); - if (resolution.isNull()) { - throw Errors.createSyntaxError("Could not resolve export"); - } else if (!resolution.isAmbiguous()) { - unambiguousNames.add(Map.entry(exportedName, resolution)); - } - } - unambiguousNames.sort((a, b) -> a.getKey().compareCharsUTF16Uncached(b.getKey())); - JSModuleNamespaceObject namespace = JSModuleNamespace.create(moduleRecord.getContext(), JSRealm.get(null), moduleRecord, unambiguousNames); - moduleRecord.setNamespace(namespace); - return namespace; - } - private static class GraphLoadingState { boolean isLoading; int pendingModulesCount; @@ -638,14 +506,15 @@ public PromiseCapabilityRecord loadRequestedModules(JSRealm realm, JSModuleRecor return pc; } - private void innerModuleLoading(JSRealm realm, GraphLoadingState state, JSModuleRecord moduleRecord) { + private void innerModuleLoading(JSRealm realm, GraphLoadingState state, AbstractModuleRecord module) { assert state.isLoading; - if (moduleRecord.getStatus() == Status.New && !state.visited.contains(moduleRecord)) { + if (module instanceof JSModuleRecord moduleRecord && moduleRecord.getStatus() == Status.New && + !state.visited.contains(moduleRecord)) { state.visited.add(moduleRecord); int requestedModuleCount = moduleRecord.getModule().getRequestedModules().size(); state.pendingModulesCount += requestedModuleCount; for (var required : moduleRecord.getModule().getRequestedModules()) { - JSModuleRecord resolved = moduleRecord.getLoadedModule(realm, required); + AbstractModuleRecord resolved = moduleRecord.getLoadedModule(realm, required); if (resolved != null) { innerModuleLoading(realm, state, resolved); } else { @@ -680,7 +549,7 @@ private void innerModuleLoading(JSRealm realm, GraphLoadingState state, JSModule public void hostLoadImportedModule(JSRealm realm, ScriptOrModule referrer, ModuleRequest moduleRequest, Object hostDefined, Object payload) { Completion moduleCompletion; try { - JSModuleRecord module = hostResolveImportedModule(realm, referrer, moduleRequest); + AbstractModuleRecord module = hostResolveImportedModule(realm, referrer, moduleRequest); moduleCompletion = Completion.forNormal(module); } catch (AbstractTruffleException e) { moduleCompletion = Completion.forThrow(getErrorObject(e)); @@ -690,8 +559,8 @@ public void hostLoadImportedModule(JSRealm realm, ScriptOrModule referrer, Modul private void finishLoadingImportedModule(JSRealm realm, ScriptOrModule referrer, ModuleRequest moduleRequest, Object payload, Completion moduleCompletion) { if (moduleCompletion.isNormal()) { - JSModuleRecord moduleResult = (JSModuleRecord) moduleCompletion.getValue(); - JSModuleRecord existing = referrer != null + AbstractModuleRecord moduleResult = (AbstractModuleRecord) moduleCompletion.getValue(); + AbstractModuleRecord existing = referrer != null ? referrer.addLoadedModule(realm, moduleRequest, moduleResult) : realm.getModuleLoader().addLoadedModule(moduleRequest, moduleResult); if (existing != null) { @@ -710,7 +579,7 @@ private void continueModuleLoading(JSRealm realm, GraphLoadingState state, Compl return; } if (moduleCompletion.isNormal()) { - innerModuleLoading(realm, state, (JSModuleRecord) moduleCompletion.getValue()); + innerModuleLoading(realm, state, (AbstractModuleRecord) moduleCompletion.getValue()); } else { state.isLoading = false; JSFunction.call(JSArguments.createOneArg(Undefined.instance, state.promiseCapability.getReject(), moduleCompletion.getValue())); @@ -725,7 +594,7 @@ private static void continueDynamicImport(Object payload, Completion moduleCompl return; } - JSModuleRecord module = (JSModuleRecord) moduleCompletion.getValue(); + AbstractModuleRecord module = (AbstractModuleRecord) moduleCompletion.getValue(); // Perform the remaining steps of ContinueDynamicImport. JSFunction.call(JSArguments.create(Undefined.instance, continuation.continueDynamicImportCallback(), promiseCapability, module)); } @@ -770,7 +639,7 @@ private int innerModuleLinking(JSRealm realm, JSModuleRecord moduleRecord, Deque Module module = moduleRecord.getModule(); for (ModuleRequest required : module.getRequestedModules()) { - JSModuleRecord requiredModule = moduleRecord.getImportedModule(required); + JSModuleRecord requiredModule = (JSModuleRecord) moduleRecord.getImportedModule(required); index = innerModuleLinking(realm, requiredModule, stack, index); assert requiredModule.getStatus() == Status.Linking || requiredModule.getStatus() == Status.Linked || requiredModule.getStatus() == Status.EvaluatingAsync || requiredModule.getStatus() == Status.Evaluated : requiredModule.getStatus(); @@ -795,11 +664,11 @@ private int innerModuleLinking(JSRealm realm, JSModuleRecord moduleRecord, Deque return index; } - private void moduleInitializeEnvironment(JSRealm realm, JSModuleRecord moduleRecord) { + private static void moduleInitializeEnvironment(JSRealm realm, JSModuleRecord moduleRecord) { assert moduleRecord.getStatus() == Status.Linking; Module module = moduleRecord.getModule(); for (ExportEntry exportEntry : module.getIndirectExportEntries()) { - ExportResolution resolution = resolveExport(moduleRecord, exportEntry.getExportName()); + ExportResolution resolution = moduleRecord.resolveExport(exportEntry.getExportName()); if (resolution.isNull() || resolution.isAmbiguous()) { throw Errors.createSyntaxError("Could not resolve indirect export entry"); } @@ -904,7 +773,7 @@ private int innerModuleEvaluation(JSRealm realm, JSModuleRecord moduleRecord, De Module module = moduleRecord.getModule(); for (ModuleRequest required : module.getRequestedModules()) { - JSModuleRecord requiredModule = moduleRecord.getImportedModule(required); + JSModuleRecord requiredModule = (JSModuleRecord) moduleRecord.getImportedModule(required); // Note: Link must have completed successfully prior to invoking this method, // so every requested module is guaranteed to resolve successfully. index = innerModuleEvaluation(realm, requiredModule, stack, index); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DebugBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DebugBuiltins.java index cfcb2b0b6b2..207c3cfdbe0 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DebugBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DebugBuiltins.java @@ -109,6 +109,7 @@ import com.oracle.truffle.js.runtime.builtins.JSGlobal; import com.oracle.truffle.js.runtime.builtins.JSOrdinary; import com.oracle.truffle.js.runtime.builtins.JSProxy; +import com.oracle.truffle.js.runtime.objects.AbstractModuleRecord; import com.oracle.truffle.js.runtime.objects.JSDynamicObject; import com.oracle.truffle.js.runtime.objects.JSModuleLoader; import com.oracle.truffle.js.runtime.objects.JSModuleRecord; @@ -582,11 +583,11 @@ public JSModuleRecord resolveImportedModule(ScriptOrModule referencingModule, Mo (key) -> new JSModuleRecord(evaluator.envParseModule(JSRealm.get(null), resolveModuleSource(referencingModule, key)), this)); } }; - JSModuleRecord module = moduleLoader.resolveImportedModule(null, ModuleRequest.create(name)); + AbstractModuleRecord module = moduleLoader.resolveImportedModule(null, ModuleRequest.create(name)); JSRealm realm = getRealm(); - evaluator.loadRequestedModules(realm, module, Undefined.instance); - evaluator.moduleLinking(realm, module); - evaluator.moduleEvaluation(realm, module); + module.loadRequestedModules(realm, Undefined.instance); + module.link(realm); + module.evaluate(realm); return Strings.fromJavaString(String.valueOf(module)); } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/commonjs/NpmCompatibleESModuleLoader.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/commonjs/NpmCompatibleESModuleLoader.java index b911f77a9a8..7ad60a22a94 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/commonjs/NpmCompatibleESModuleLoader.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/commonjs/NpmCompatibleESModuleLoader.java @@ -77,6 +77,7 @@ import com.oracle.truffle.js.runtime.Strings; import com.oracle.truffle.js.runtime.builtins.JSFunction; import com.oracle.truffle.js.runtime.builtins.JSFunctionObject; +import com.oracle.truffle.js.runtime.objects.AbstractModuleRecord; import com.oracle.truffle.js.runtime.objects.DefaultESModuleLoader; import com.oracle.truffle.js.runtime.objects.JSDynamicObject; import com.oracle.truffle.js.runtime.objects.JSModuleData; @@ -121,7 +122,7 @@ private NpmCompatibleESModuleLoader(JSRealm realm) { */ @TruffleBoundary @Override - public JSModuleRecord resolveImportedModule(ScriptOrModule referencingModule, ModuleRequest moduleRequest) { + public AbstractModuleRecord resolveImportedModule(ScriptOrModule referencingModule, ModuleRequest moduleRequest) { String specifier = moduleRequest.specifier().toJavaStringUncached(); log("IMPORT resolve ", specifier); String moduleReplacementName = getCoreModuleReplacement(realm, specifier); @@ -156,10 +157,10 @@ public JSModuleRecord resolveImportedModule(ScriptOrModule referencingModule, Mo } } - private JSModuleRecord loadCoreModuleReplacement(ScriptOrModule referencingModule, ModuleRequest moduleRequest, String moduleReplacementName) { + private AbstractModuleRecord loadCoreModuleReplacement(ScriptOrModule referencingModule, ModuleRequest moduleRequest, String moduleReplacementName) { String specifier = moduleRequest.specifier().toJavaStringUncached(); log("IMPORT resolve built-in ", specifier); - JSModuleRecord existingModule = moduleMap.get(specifier); + AbstractModuleRecord existingModule = moduleMap.get(specifier); if (existingModule != null) { log("IMPORT resolve built-in from cache ", specifier); return existingModule; @@ -200,8 +201,8 @@ private JSModuleRecord loadCoreModuleReplacement(ScriptOrModule referencingModul return record; } - private JSModuleRecord tryLoadingAsCommonjsModule(String specifier) { - JSModuleRecord existingModule = moduleMap.get(specifier); + private AbstractModuleRecord tryLoadingAsCommonjsModule(String specifier) { + AbstractModuleRecord existingModule = moduleMap.get(specifier); if (existingModule != null) { log("IMPORT resolve built-in from cache ", specifier); return existingModule; diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ReadImportBindingNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ReadImportBindingNode.java index 903fa719fbc..09292c199d3 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ReadImportBindingNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ReadImportBindingNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -132,11 +132,12 @@ final Object doGetNamespace(ExportResolution.Resolved resolution, @Cached InlinedBranchProfile slowPath) { JSModuleRecord module = resolution.getModule(); assert module.getStatus().compareTo(Status.Linked) >= 0 : module.getStatus(); - if (CompilerDirectives.injectBranchProbability(CompilerDirectives.FASTPATH_PROBABILITY, module.getNamespace() != null)) { - return module.getNamespace(); + var namespace = module.getModuleNamespaceOrNull(); + if (CompilerDirectives.injectBranchProbability(CompilerDirectives.FASTPATH_PROBABILITY, namespace != null)) { + return namespace; } else { slowPath.enter(this); - return getLanguage().getJSContext().getEvaluator().getModuleNamespace(module); + return module.getModuleNamespace(); } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveNamedImportNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveNamedImportNode.java index 2bd0a6bf2bd..9d43c52e61d 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveNamedImportNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveNamedImportNode.java @@ -51,7 +51,6 @@ import com.oracle.truffle.js.nodes.access.JSWriteFrameSlotNode; import com.oracle.truffle.js.nodes.control.StatementNode; import com.oracle.truffle.js.runtime.Errors; -import com.oracle.truffle.js.runtime.Evaluator; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.objects.ExportResolution; import com.oracle.truffle.js.runtime.objects.JSModuleRecord; @@ -86,11 +85,10 @@ public static StatementNode create(JSContext context, JavaScriptNode moduleNode, @Override public Object execute(VirtualFrame frame) { JSModuleRecord referrer = (JSModuleRecord) moduleNode.execute(frame); - Evaluator evaluator = context.getEvaluator(); // Let importedModule be GetImportedModule(module, in.[[ModuleRequest]]). - JSModuleRecord importedModule = referrer.getImportedModule(moduleRequest); + JSModuleRecord importedModule = (JSModuleRecord) referrer.getImportedModule(moduleRequest); // Let resolution be importedModule.ResolveExport(in.[[ImportName]]). - ExportResolution resolution = resolutionProfile.profile(evaluator.resolveExport(importedModule, importName)); + ExportResolution resolution = resolutionProfile.profile(importedModule.resolveExport(importName)); // If resolution is null or resolution is "ambiguous", throw SyntaxError. if (resolution.isNull() || resolution.isAmbiguous()) { String message = "The requested module '%s' does not provide an export named '%s'"; @@ -98,7 +96,7 @@ public Object execute(VirtualFrame frame) { } Object resolutionOrNamespace; if (resolution.isNamespace()) { - resolutionOrNamespace = evaluator.getModuleNamespace(resolution.getModule()); + resolutionOrNamespace = resolution.getModule().getModuleNamespace(); } else { resolutionOrNamespace = resolution; } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveStarImportNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveStarImportNode.java index 0d086bba836..d0d1cfeba74 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveStarImportNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveStarImportNode.java @@ -78,10 +78,10 @@ public static StatementNode create(JSContext context, JavaScriptNode moduleNode, public Object execute(VirtualFrame frame) { JSModuleRecord referrer = (JSModuleRecord) moduleNode.execute(frame); // Let importedModule be GetImportedModule(module, in.[[ModuleRequest]]). - JSModuleRecord importedModule = referrer.getImportedModule(moduleRequest); + JSModuleRecord importedModule = (JSModuleRecord) referrer.getImportedModule(moduleRequest); // If in.[[ImportName]] is namespace-object, then // Let namespace be GetModuleNamespace(importedModule) - JSDynamicObject namespace = context.getEvaluator().getModuleNamespace(importedModule); + JSDynamicObject namespace = importedModule.getModuleNamespace(); // envRec.CreateImmutableBinding(in.[[LocalName]], true). // Call envRec.InitializeBinding(in.[[LocalName]], namespace). writeLocalNode.executeWrite(frame, namespace); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java index 0c59c1da4a3..ee53166f393 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java @@ -342,7 +342,7 @@ public Object executeInRealm(VirtualFrame frame) { JSModuleRecord module = (JSModuleRecord) moduleRecordArgument.execute(frame); JSRealm realm = getRealm(); - JSPromiseObject loadPromise = (JSPromiseObject) context.getEvaluator().loadRequestedModules(realm, module, Undefined.instance).getPromise(); + JSPromiseObject loadPromise = (JSPromiseObject) module.loadRequestedModules(realm, Undefined.instance).getPromise(); JSFunctionObject onRejected = createOnRejectedClosure(context, realm, importPromiseCapability); JSFunctionObject linkAndEvaluate = createLinkAndEvaluateClosure(context, realm, module, importPromiseCapability, onRejected); @@ -396,11 +396,11 @@ protected Object executeInRealm(VirtualFrame frame) { assert realm == JSFunction.getRealm(JSFrameUtil.getFunctionObject(frame)); try { // If link is an abrupt completion, reject the promise from import(). - context.getEvaluator().moduleLinking(realm, moduleRecord); + moduleRecord.link(realm); // Evaluate() should always return a promise. // Yet, if top-level-await is disabled, returns/throws the result instead. - Object evaluatePromise = context.getEvaluator().moduleEvaluation(realm, moduleRecord); + Object evaluatePromise = moduleRecord.evaluate(realm); if (context.isOptionTopLevelAwait()) { assert evaluatePromise instanceof JSPromiseObject : evaluatePromise; JSFunctionObject onFulfilled = createFulfilledClosure(context, realm, captures); @@ -408,7 +408,7 @@ protected Object executeInRealm(VirtualFrame frame) { } else { // Rethrow any previous execution errors. moduleRecord.getExecutionResultOrThrow(); - var namespace = context.getEvaluator().getModuleNamespace(moduleRecord); + var namespace = moduleRecord.getModuleNamespace(); callPromiseResolve.executeCall(JSArguments.createOneArg(Undefined.instance, importPromiseCapability.getResolve(), namespace)); } } catch (AbstractTruffleException ex) { @@ -449,7 +449,7 @@ public Object execute(VirtualFrame frame) { PromiseCapabilityRecord promiseCapability = captures.promiseCapability; JSModuleRecord moduleRecord = captures.moduleRecord; - var namespace = cx.getEvaluator().getModuleNamespace(moduleRecord); + var namespace = moduleRecord.getModuleNamespace(); callPromiseResolve.executeCall(JSArguments.createOneArg(Undefined.instance, promiseCapability.getResolve(), namespace)); return Undefined.instance; } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java index eecc6d1103f..ef7fea59b45 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java @@ -50,8 +50,6 @@ import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.nodes.JavaScriptNode; import com.oracle.truffle.js.nodes.ScriptNode; -import com.oracle.truffle.js.runtime.objects.ExportResolution; -import com.oracle.truffle.js.runtime.objects.JSDynamicObject; import com.oracle.truffle.js.runtime.objects.JSModuleData; import com.oracle.truffle.js.runtime.objects.JSModuleRecord; import com.oracle.truffle.js.runtime.objects.PromiseCapabilityRecord; @@ -111,10 +109,6 @@ public interface Evaluator { Object moduleEvaluation(JSRealm realm, JSModuleRecord moduleRecord); - JSDynamicObject getModuleNamespace(JSModuleRecord moduleRecord); - - ExportResolution resolveExport(JSModuleRecord moduleRecord, TruffleString exportName); - /** * Parses a script string. Returns an executable script object. */ diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSModuleNamespace.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSModuleNamespace.java index 3b3cd7ecb9a..4c40f9c4f3d 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSModuleNamespace.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSModuleNamespace.java @@ -160,7 +160,7 @@ public static Object getBindingValue(ExportResolution binding) { throw Errors.createReferenceErrorNotDefined(bindingName, null); } if (binding.isNamespace()) { - return targetModule.getContext().getEvaluator().getModuleNamespace(targetModule); + return targetModule.getModuleNamespace(); } FrameDescriptor targetEnvDesc = targetEnv.getFrameDescriptor(); int slot = JSFrameUtil.findRequiredFrameSlotIndex(targetEnvDesc, bindingName); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/AbstractModuleRecord.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/AbstractModuleRecord.java new file mode 100644 index 00000000000..a00ad3ed123 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/AbstractModuleRecord.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.runtime.objects; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.strings.TruffleString; +import com.oracle.truffle.js.runtime.JSContext; +import com.oracle.truffle.js.runtime.JSRealm; +import com.oracle.truffle.js.runtime.util.Pair; + +/** + * Abstract Module Record. + */ +public abstract class AbstractModuleRecord extends ScriptOrModule { + + public AbstractModuleRecord(JSContext context, Source source) { + super(context, source); + } + + public abstract PromiseCapabilityRecord loadRequestedModules(JSRealm realm, Object hostDefined); + + public abstract void link(JSRealm realm); + + public abstract Object evaluate(JSRealm realm); + + @TruffleBoundary + public final Collection getExportedNames() { + return getExportedNames(new HashSet<>()); + } + + public abstract Collection getExportedNames(Set exportStarSet); + + @TruffleBoundary + public final ExportResolution resolveExport(TruffleString exportName) { + return resolveExport(exportName, new HashSet<>()); + } + + public abstract ExportResolution resolveExport(TruffleString exportName, Set> resolveSet); + + public JSDynamicObject getModuleNamespace() { + return Undefined.instance; + } + +} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java index 37b9348ae1e..bd717cf9bfa 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java @@ -72,7 +72,7 @@ public class DefaultESModuleLoader implements JSModuleLoader { private static final int JSON_MODULE_TYPE = 1 << 1; protected final JSRealm realm; - protected final Map moduleMap = new HashMap<>(); + protected final Map moduleMap = new HashMap<>(); public static DefaultESModuleLoader create(JSRealm realm) { return new DefaultESModuleLoader(realm); @@ -96,7 +96,7 @@ protected URI asURI(String specifier) { } @Override - public JSModuleRecord resolveImportedModule(ScriptOrModule referrer, ModuleRequest moduleRequest) { + public AbstractModuleRecord resolveImportedModule(ScriptOrModule referrer, ModuleRequest moduleRequest) { String refPath = null; String refPathOrName = null; if (referrer != null) { @@ -186,7 +186,7 @@ private boolean bareSpecifierDirectLookup(String specifier) { return !(specifier.startsWith(SLASH) || specifier.startsWith(DOT_SLASH) || specifier.startsWith(DOT_DOT_SLASH)); } - protected JSModuleRecord loadModuleFromUrl(ScriptOrModule referrer, ModuleRequest moduleRequest, TruffleFile maybeModuleFile, String maybeCanonicalPath) throws IOException { + protected AbstractModuleRecord loadModuleFromUrl(ScriptOrModule referrer, ModuleRequest moduleRequest, TruffleFile maybeModuleFile, String maybeCanonicalPath) throws IOException { TruffleFile moduleFile = maybeModuleFile; String canonicalPath; TruffleLanguage.Env env = realm.getEnv(); @@ -200,7 +200,7 @@ protected JSModuleRecord loadModuleFromUrl(ScriptOrModule referrer, ModuleReques canonicalPath = maybeCanonicalPath; } - JSModuleRecord existingModule = moduleMap.get(canonicalPath); + AbstractModuleRecord existingModule = moduleMap.get(canonicalPath); if (existingModule != null) { return existingModule; } @@ -249,7 +249,7 @@ private static boolean isModuleType(int moduleType, int expectedType) { } @Override - public JSModuleRecord addLoadedModule(ModuleRequest moduleRequest, JSModuleRecord moduleRecord) { + public AbstractModuleRecord addLoadedModule(ModuleRequest moduleRequest, AbstractModuleRecord moduleRecord) { String canonicalPath = getCanonicalPath(moduleRecord.getSource()); return moduleMap.putIfAbsent(canonicalPath, moduleRecord); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleLoader.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleLoader.java index 1262c3f596a..a274b3a877e 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleLoader.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleLoader.java @@ -43,10 +43,10 @@ import com.oracle.js.parser.ir.Module.ModuleRequest; public interface JSModuleLoader { - JSModuleRecord resolveImportedModule(ScriptOrModule referencingModule, ModuleRequest moduleRequest); + AbstractModuleRecord resolveImportedModule(ScriptOrModule referencingModule, ModuleRequest moduleRequest); @SuppressWarnings("unused") - default JSModuleRecord addLoadedModule(ModuleRequest moduleRequest, JSModuleRecord moduleRecord) { + default AbstractModuleRecord addLoadedModule(ModuleRequest moduleRequest, AbstractModuleRecord moduleRecord) { throw new UnsupportedOperationException(); } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java index 5e557c8d90c..4e688513e62 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java @@ -41,26 +41,38 @@ package com.oracle.truffle.js.runtime.objects; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Map; +import java.util.Set; import org.graalvm.collections.EconomicMap; +import com.oracle.js.parser.ir.Module; +import com.oracle.js.parser.ir.Module.ExportEntry; import com.oracle.js.parser.ir.Module.ModuleRequest; +import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.frame.FrameDescriptor; import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.strings.TruffleString; +import com.oracle.truffle.js.runtime.Errors; import com.oracle.truffle.js.runtime.JSRealm; import com.oracle.truffle.js.runtime.JSRuntime; import com.oracle.truffle.js.runtime.Strings; import com.oracle.truffle.js.runtime.builtins.JSFunctionData; +import com.oracle.truffle.js.runtime.builtins.JSModuleNamespace; +import com.oracle.truffle.js.runtime.builtins.JSModuleNamespaceObject; import com.oracle.truffle.js.runtime.builtins.JSOrdinary; +import com.oracle.truffle.js.runtime.util.Pair; /** * Source Text Module Record. */ -public class JSModuleRecord extends ScriptOrModule { +public class JSModuleRecord extends AbstractModuleRecord { public enum Status { New, @@ -84,7 +96,7 @@ public enum Status { private Object executionResult; /** Lazily initialized Module Namespace object ({@code [[Namespace]]}). */ - private JSDynamicObject namespace; + private JSModuleNamespaceObject namespace; /** Lazily initialized frame ({@code [[Environment]]}). */ private MaterializedFrame environment; /** Lazily initialized import.meta object ({@code [[ImportMeta]]}). */ @@ -106,7 +118,7 @@ public enum Status { */ private int dfsAncestorIndex = -1; - private EconomicMap loadedModules = EconomicMap.create(); + private EconomicMap loadedModules = EconomicMap.create(); public JSModuleRecord(JSModuleData parsedModule, JSModuleLoader moduleLoader) { super(parsedModule.getContext(), parsedModule.getSource()); @@ -164,15 +176,6 @@ public void setEvaluationError(Throwable evaluationError) { this.evaluationError = evaluationError; } - public JSDynamicObject getNamespace() { - return namespace; - } - - public void setNamespace(JSDynamicObject namespace) { - assert this.namespace == null; - this.namespace = namespace; - } - public MaterializedFrame getEnvironment() { return environment; } @@ -333,22 +336,161 @@ public JSModuleRecord getCycleRoot() { @TruffleBoundary @Override - public JSModuleRecord getLoadedModule(JSRealm realm, ModuleRequest moduleRequest) { + public AbstractModuleRecord getLoadedModule(JSRealm realm, ModuleRequest moduleRequest) { return loadedModules.get(moduleRequest); } @TruffleBoundary @Override - public JSModuleRecord addLoadedModule(JSRealm realm, ModuleRequest moduleRequest, JSModuleRecord module) { + public AbstractModuleRecord addLoadedModule(JSRealm realm, ModuleRequest moduleRequest, AbstractModuleRecord module) { return loadedModules.putIfAbsent(moduleRequest, module); } @TruffleBoundary - public JSModuleRecord getImportedModule(ModuleRequest moduleRequest) { + public AbstractModuleRecord getImportedModule(ModuleRequest moduleRequest) { assert loadedModules.containsKey(moduleRequest) : moduleRequest; return loadedModules.get(moduleRequest); } + @Override + public Collection getExportedNames(Set exportStarSet) { + CompilerAsserts.neverPartOfCompilation(); + if (exportStarSet.contains(this)) { + // Assert: We've reached the starting point of an import * circularity. + return Collections.emptySortedSet(); + } + exportStarSet.add(this); + Collection exportedNames = new HashSet<>(); + for (ExportEntry exportEntry : getModule().getLocalExportEntries()) { + // Assert: module provides the direct binding for this export. + exportedNames.add(exportEntry.getExportName()); + } + for (ExportEntry exportEntry : getModule().getIndirectExportEntries()) { + // Assert: module imports a specific binding for this export. + exportedNames.add(exportEntry.getExportName()); + } + for (ExportEntry exportEntry : getModule().getStarExportEntries()) { + JSModuleRecord requestedModule = (JSModuleRecord) getImportedModule(exportEntry.getModuleRequest()); + Collection starNames = requestedModule.getExportedNames(exportStarSet); + for (TruffleString starName : starNames) { + if (!starName.equals(com.oracle.js.parser.ir.Module.DEFAULT_NAME)) { + if (!exportedNames.contains(starName)) { + exportedNames.add(starName); + } + } + } + } + return exportedNames; + } + + /** + * ResolveExport attempts to resolve an imported binding to the actual defining module and local + * binding name. The defining module may be the module represented by the Module Record this + * method was invoked on or some other module that is imported by that module. The parameter + * resolveSet is use to detect unresolved circular import/export paths. If a pair consisting of + * specific Module Record and exportName is reached that is already in resolveSet, an import + * circularity has been encountered. Before recursively calling ResolveExport, a pair consisting + * of module and exportName is added to resolveSet. + * + * If a defining module is found a Record {[[module]], [[bindingName]]} is returned. This record + * identifies the resolved binding of the originally requested export. If no definition was + * found or the request is found to be circular, null is returned. If the request is found to be + * ambiguous, the string "ambiguous" is returned. + */ + @Override + public ExportResolution resolveExport(TruffleString exportName, Set> resolveSet) { + CompilerAsserts.neverPartOfCompilation(); + Pair resolved = new Pair<>(this, exportName); + if (resolveSet.contains(resolved)) { + // Assert: this is a circular import request. + return ExportResolution.notFound(); + } + resolveSet.add(resolved); + for (ExportEntry exportEntry : getModule().getLocalExportEntries()) { + if (exportEntry.getExportName().equals(exportName)) { + // Assert: module provides the direct binding for this export. + return ExportResolution.resolved(this, exportEntry.getLocalName()); + } + } + for (ExportEntry exportEntry : getModule().getIndirectExportEntries()) { + if (exportEntry.getExportName().equals(exportName)) { + JSModuleRecord importedModule = (JSModuleRecord) getImportedModule(exportEntry.getModuleRequest()); + if (exportEntry.getImportName().equals(Module.STAR_NAME)) { + // Assert: module does not provide the direct binding for this export. + return ExportResolution.resolved(importedModule, Module.NAMESPACE_EXPORT_BINDING_NAME); + } else { + // Assert: module imports a specific binding for this export. + return importedModule.resolveExport(exportEntry.getImportName(), resolveSet); + } + } + } + if (exportName.equals(Module.DEFAULT_NAME)) { + // Assert: A default export was not explicitly defined by this module. + return ExportResolution.notFound(); + // NOTE: A default export cannot be provided by an `export *` or `export * from "mod"`. + } + ExportResolution starResolution = ExportResolution.notFound(); + for (ExportEntry exportEntry : getModule().getStarExportEntries()) { + JSModuleRecord importedModule = (JSModuleRecord) getImportedModule(exportEntry.getModuleRequest()); + ExportResolution resolution = importedModule.resolveExport(exportName, resolveSet); + if (resolution.isAmbiguous()) { + return resolution; + } + if (!resolution.isNull()) { + if (starResolution.isNull()) { + starResolution = resolution; + } else { + // Assert: there is more than one * import that includes the requested name. + if (!resolution.equals(starResolution)) { + return ExportResolution.ambiguous(); + } + } + } + } + return starResolution; + } + + public JSDynamicObject getModuleNamespaceOrNull() { + return namespace; + } + + @TruffleBoundary + @Override + public JSDynamicObject getModuleNamespace() { + if (namespace != null) { + return namespace; + } + Collection exportedNames = getExportedNames(); + List> unambiguousNames = new ArrayList<>(); + for (TruffleString exportedName : exportedNames) { + ExportResolution resolution = resolveExport(exportedName); + if (resolution.isNull()) { + throw Errors.createSyntaxError("Could not resolve export"); + } else if (!resolution.isAmbiguous()) { + unambiguousNames.add(Map.entry(exportedName, resolution)); + } + } + unambiguousNames.sort((a, b) -> a.getKey().compareCharsUTF16Uncached(b.getKey())); + JSModuleNamespaceObject ns = JSModuleNamespace.create(getContext(), JSRealm.get(null), this, unambiguousNames); + this.namespace = ns; + return ns; + } + + @Override + public PromiseCapabilityRecord loadRequestedModules(JSRealm realm, Object hostDefinedArg) { + return context.getEvaluator().loadRequestedModules(realm, this, hostDefinedArg); + } + + @Override + public void link(JSRealm realm) { + context.getEvaluator().moduleLinking(realm, this); + } + + @Override + public Object evaluate(JSRealm realm) { + return context.getEvaluator().moduleEvaluation(realm, this); + } + @Override public void rememberImportedModuleSource(TruffleString moduleSpecifier, Source moduleSource) { parsedModule.rememberImportedModuleSource(moduleSpecifier, moduleSource); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/ScriptOrModule.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/ScriptOrModule.java index 4d3afd6288e..ef5b95e6560 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/ScriptOrModule.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/ScriptOrModule.java @@ -80,12 +80,12 @@ public final Source getSource() { } @TruffleBoundary - public JSModuleRecord getLoadedModule(JSRealm realm, ModuleRequest moduleRequest) { + public AbstractModuleRecord getLoadedModule(JSRealm realm, ModuleRequest moduleRequest) { return realm.getModuleLoader().resolveImportedModule(this, moduleRequest); } @TruffleBoundary - public JSModuleRecord addLoadedModule(JSRealm realm, ModuleRequest moduleRequest, JSModuleRecord moduleRecord) { + public AbstractModuleRecord addLoadedModule(JSRealm realm, ModuleRequest moduleRequest, AbstractModuleRecord moduleRecord) { return realm.getModuleLoader().addLoadedModule(moduleRequest, moduleRecord); } diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java index 0327dd948ba..fe21a17a0ca 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java @@ -172,7 +172,6 @@ import com.oracle.truffle.js.nodes.access.GetPrototypeNode; import com.oracle.truffle.js.nodes.arguments.AccessIndexedArgumentNode; import com.oracle.truffle.js.nodes.function.ConstructorRootNode; -import com.oracle.truffle.js.parser.GraalJSEvaluator; import com.oracle.truffle.js.parser.GraalJSParserHelper; import com.oracle.truffle.js.parser.JSParser; import com.oracle.truffle.js.parser.JavaScriptTranslator; @@ -2731,7 +2730,7 @@ private WeakCallback updateWeakCallback(Object object, long reference, long data // ClearWeak() called on a module that cannot be weak yet return null; } - target = moduleRecord.getContext().getEvaluator().getModuleNamespace(moduleRecord); + target = moduleRecord.getModuleNamespace(); key = HIDDEN_WEAK_CALLBACK_SUBSTITUTE; } else { System.err.println("Weak references not supported for " + object); @@ -3805,12 +3804,11 @@ public Object moduleCompile(Object context, Object sourceCode, Object name, Obje public void moduleInstantiate(Object context, Object module, long resolveCallback) { JSRealm jsRealm = (JSRealm) context; JSModuleRecord moduleRecord = (JSModuleRecord) module; - JSContext jsContext = jsRealm.getContext(); ESModuleLoader loader = getModuleLoader(); loader.setResolver(resolveCallback); try { - jsContext.getEvaluator().loadRequestedModules(jsRealm, moduleRecord, moduleRecord.getHostDefined()); - jsContext.getEvaluator().moduleLinking(jsRealm, moduleRecord); + moduleRecord.loadRequestedModules(jsRealm, moduleRecord.getHostDefined()); + moduleRecord.link(jsRealm); } finally { loader.setResolver(0); } @@ -3818,11 +3816,10 @@ public void moduleInstantiate(Object context, Object module, long resolveCallbac public Object moduleEvaluate(Object context, Object module) { JSRealm jsRealm = (JSRealm) context; - JSContext jsContext = jsRealm.getContext(); JSModuleRecord moduleRecord = (JSModuleRecord) module; if (!moduleRecord.hasBeenEvaluated()) { - jsContext.getEvaluator().moduleEvaluation(jsRealm, moduleRecord); + moduleRecord.evaluate(jsRealm); } PromiseCapabilityRecord promiseCapability = moduleRecord.getTopLevelCapability(); @@ -3873,8 +3870,7 @@ public Object moduleGetModuleRequests(Object module) { public Object moduleGetNamespace(Object module) { JSModuleRecord record = (JSModuleRecord) module; - GraalJSEvaluator graalEvaluator = (GraalJSEvaluator) record.getContext().getEvaluator(); - return graalEvaluator.getModuleNamespace(record); + return record.getModuleNamespace(); } public int moduleGetIdentityHash(Object module) { From e7cb26f7f93d58409ada54e1cb258fe459ee98e4 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 14 Aug 2024 16:24:11 +0200 Subject: [PATCH 195/265] Change LoadRequestedModules to return the Promise object directly. --- .../src/com/oracle/truffle/js/parser/GraalJSEvaluator.java | 6 +++--- .../com/oracle/truffle/js/nodes/promise/ImportCallNode.java | 2 +- .../src/com/oracle/truffle/js/runtime/Evaluator.java | 4 ++-- .../truffle/js/runtime/objects/AbstractModuleRecord.java | 3 ++- .../oracle/truffle/js/runtime/objects/JSModuleRecord.java | 3 ++- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java index f6ed188ed65..c328a4bbc04 100644 --- a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java +++ b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java @@ -293,7 +293,7 @@ private Object evalModule(JSRealm realm) { ModuleRequest moduleRequest = ModuleRequest.create(Strings.fromJavaString(source.getName())); realm.getModuleLoader().addLoadedModule(moduleRequest, moduleRecord); - JSPromiseObject loadPromise = (JSPromiseObject) moduleRecord.loadRequestedModules(realm, Undefined.instance).getPromise(); + JSPromiseObject loadPromise = moduleRecord.loadRequestedModules(realm, Undefined.instance); assert !JSPromise.isPending(loadPromise); // If loading failed, we must not perform module linking. if (JSPromise.isRejected(loadPromise)) { @@ -494,7 +494,7 @@ private static class GraphLoadingState { @TruffleBoundary @Override - public PromiseCapabilityRecord loadRequestedModules(JSRealm realm, JSModuleRecord moduleRecord, Object hostDefined) { + public JSPromiseObject loadRequestedModules(JSRealm realm, JSModuleRecord moduleRecord, Object hostDefined) { PromiseCapabilityRecord pc = NewPromiseCapabilityNode.createDefault(realm); GraphLoadingState state = new GraphLoadingState(pc, hostDefined); try { @@ -503,7 +503,7 @@ public PromiseCapabilityRecord loadRequestedModules(JSRealm realm, JSModuleRecor assert false : e; // should not throw throw e; } - return pc; + return (JSPromiseObject) pc.getPromise(); } private void innerModuleLoading(JSRealm realm, GraphLoadingState state, AbstractModuleRecord module) { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java index ee53166f393..bf85ba4f7be 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java @@ -342,7 +342,7 @@ public Object executeInRealm(VirtualFrame frame) { JSModuleRecord module = (JSModuleRecord) moduleRecordArgument.execute(frame); JSRealm realm = getRealm(); - JSPromiseObject loadPromise = (JSPromiseObject) module.loadRequestedModules(realm, Undefined.instance).getPromise(); + JSPromiseObject loadPromise = module.loadRequestedModules(realm, Undefined.instance); JSFunctionObject onRejected = createOnRejectedClosure(context, realm, importPromiseCapability); JSFunctionObject linkAndEvaluate = createLinkAndEvaluateClosure(context, realm, module, importPromiseCapability, onRejected); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java index ef7fea59b45..e3411d10f43 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java @@ -50,9 +50,9 @@ import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.nodes.JavaScriptNode; import com.oracle.truffle.js.nodes.ScriptNode; +import com.oracle.truffle.js.runtime.builtins.JSPromiseObject; import com.oracle.truffle.js.runtime.objects.JSModuleData; import com.oracle.truffle.js.runtime.objects.JSModuleRecord; -import com.oracle.truffle.js.runtime.objects.PromiseCapabilityRecord; import com.oracle.truffle.js.runtime.objects.ScriptOrModule; public interface Evaluator { @@ -103,7 +103,7 @@ public interface Evaluator { void hostLoadImportedModule(JSRealm realm, ScriptOrModule referrer, Module.ModuleRequest moduleRequest, Object hostDefined, Object payload); - PromiseCapabilityRecord loadRequestedModules(JSRealm realm, JSModuleRecord moduleRecord, Object hostDefined); + JSPromiseObject loadRequestedModules(JSRealm realm, JSModuleRecord moduleRecord, Object hostDefined); void moduleLinking(JSRealm realm, JSModuleRecord moduleRecord); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/AbstractModuleRecord.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/AbstractModuleRecord.java index a00ad3ed123..764207066b4 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/AbstractModuleRecord.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/AbstractModuleRecord.java @@ -49,6 +49,7 @@ import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRealm; +import com.oracle.truffle.js.runtime.builtins.JSPromiseObject; import com.oracle.truffle.js.runtime.util.Pair; /** @@ -60,7 +61,7 @@ public AbstractModuleRecord(JSContext context, Source source) { super(context, source); } - public abstract PromiseCapabilityRecord loadRequestedModules(JSRealm realm, Object hostDefined); + public abstract JSPromiseObject loadRequestedModules(JSRealm realm, Object hostDefined); public abstract void link(JSRealm realm); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java index 4e688513e62..af119fe6ed8 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java @@ -67,6 +67,7 @@ import com.oracle.truffle.js.runtime.builtins.JSModuleNamespace; import com.oracle.truffle.js.runtime.builtins.JSModuleNamespaceObject; import com.oracle.truffle.js.runtime.builtins.JSOrdinary; +import com.oracle.truffle.js.runtime.builtins.JSPromiseObject; import com.oracle.truffle.js.runtime.util.Pair; /** @@ -477,7 +478,7 @@ public JSDynamicObject getModuleNamespace() { } @Override - public PromiseCapabilityRecord loadRequestedModules(JSRealm realm, Object hostDefinedArg) { + public JSPromiseObject loadRequestedModules(JSRealm realm, Object hostDefinedArg) { return context.getEvaluator().loadRequestedModules(realm, this, hostDefinedArg); } From ee4754c8bad294b74d5cea097c40327e1133f66b Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 14 Aug 2024 06:15:42 +0200 Subject: [PATCH 196/265] Introduce synchronous LoadRequestedModules. --- .../com/oracle/truffle/js/parser/GraalJSEvaluator.java | 9 ++------- .../com/oracle/truffle/js/builtins/DebugBuiltins.java | 2 +- .../js/runtime/objects/AbstractModuleRecord.java | 10 ++++++++++ .../com/oracle/truffle/trufflenode/GraalJSAccess.java | 2 +- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java index c328a4bbc04..2ce302435c4 100644 --- a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java +++ b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java @@ -111,7 +111,6 @@ import com.oracle.truffle.js.runtime.builtins.JSFunction; import com.oracle.truffle.js.runtime.builtins.JSFunctionData; import com.oracle.truffle.js.runtime.builtins.JSFunctionObject; -import com.oracle.truffle.js.runtime.builtins.JSPromise; import com.oracle.truffle.js.runtime.builtins.JSPromiseObject; import com.oracle.truffle.js.runtime.objects.AbstractModuleRecord; import com.oracle.truffle.js.runtime.objects.Completion; @@ -293,12 +292,8 @@ private Object evalModule(JSRealm realm) { ModuleRequest moduleRequest = ModuleRequest.create(Strings.fromJavaString(source.getName())); realm.getModuleLoader().addLoadedModule(moduleRequest, moduleRecord); - JSPromiseObject loadPromise = moduleRecord.loadRequestedModules(realm, Undefined.instance); - assert !JSPromise.isPending(loadPromise); - // If loading failed, we must not perform module linking. - if (JSPromise.isRejected(loadPromise)) { - throw JSRuntime.getException(loadPromise.getPromiseResult(), this); - } + moduleRecord.loadRequestedModulesSync(realm, Undefined.instance); + // Note: If loading failed, we must not perform module linking. moduleRecord.link(realm); Object promise = moduleRecord.evaluate(realm); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DebugBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DebugBuiltins.java index 207c3cfdbe0..34f7dc48ea7 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DebugBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DebugBuiltins.java @@ -585,7 +585,7 @@ public JSModuleRecord resolveImportedModule(ScriptOrModule referencingModule, Mo }; AbstractModuleRecord module = moduleLoader.resolveImportedModule(null, ModuleRequest.create(name)); JSRealm realm = getRealm(); - module.loadRequestedModules(realm, Undefined.instance); + module.loadRequestedModulesSync(realm, Undefined.instance); module.link(realm); module.evaluate(realm); return Strings.fromJavaString(String.valueOf(module)); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/AbstractModuleRecord.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/AbstractModuleRecord.java index 764207066b4..f3ad4324c8a 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/AbstractModuleRecord.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/AbstractModuleRecord.java @@ -49,6 +49,8 @@ import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRealm; +import com.oracle.truffle.js.runtime.JSRuntime; +import com.oracle.truffle.js.runtime.builtins.JSPromise; import com.oracle.truffle.js.runtime.builtins.JSPromiseObject; import com.oracle.truffle.js.runtime.util.Pair; @@ -63,6 +65,14 @@ public AbstractModuleRecord(JSContext context, Source source) { public abstract JSPromiseObject loadRequestedModules(JSRealm realm, Object hostDefined); + public final void loadRequestedModulesSync(JSRealm realm, Object hostDefined) { + JSPromiseObject loadPromise = loadRequestedModules(realm, hostDefined); + assert !JSPromise.isPending(loadPromise); + if (JSPromise.isRejected(loadPromise)) { + throw JSRuntime.getException(JSPromise.getPromiseResult(loadPromise)); + } + } + public abstract void link(JSRealm realm); public abstract Object evaluate(JSRealm realm); diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java index fe21a17a0ca..5cdeff86fd6 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java @@ -3807,7 +3807,7 @@ public void moduleInstantiate(Object context, Object module, long resolveCallbac ESModuleLoader loader = getModuleLoader(); loader.setResolver(resolveCallback); try { - moduleRecord.loadRequestedModules(jsRealm, moduleRecord.getHostDefined()); + moduleRecord.loadRequestedModulesSync(jsRealm, moduleRecord.getHostDefined()); moduleRecord.link(jsRealm); } finally { loader.setResolver(0); From 336fd2758015b7e036706a9f0359902304c84432 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 12 Aug 2024 14:55:59 +0200 Subject: [PATCH 197/265] Implement source phase imports proposal. --- .../com/oracle/js/parser/AbstractParser.java | 14 ++- .../src/com/oracle/js/parser/Parser.java | 112 +++++++++++++++--- .../oracle/js/parser/ScriptEnvironment.java | 12 +- .../src/com/oracle/js/parser/ir/CallNode.java | 16 ++- .../src/com/oracle/js/parser/ir/Module.java | 33 +++++- .../truffle/js/parser/GraalJSEvaluator.java | 39 ++++-- .../js/parser/GraalJSParserHelper.java | 1 + .../truffle/js/parser/GraalJSTranslator.java | 14 ++- .../AbstractModuleSourcePrototype.java | 103 ++++++++++++++++ .../js/builtins/ConstructorBuiltins.java | 2 + .../oracle/truffle/js/nodes/NodeFactory.java | 10 +- .../nodes/module/ResolveSourceImportNode.java | 95 +++++++++++++++ .../js/nodes/promise/ImportCallNode.java | 31 ++--- .../truffle/js/runtime/JSContextOptions.java | 10 ++ .../truffle/js/runtime/JSLanguageOptions.java | 3 + .../truffle/js/runtime/JSParserOptions.java | 6 +- .../oracle/truffle/js/runtime/JSRealm.java | 25 ++++ .../runtime/objects/AbstractModuleRecord.java | 2 + .../js/runtime/objects/JSModuleRecord.java | 9 ++ 19 files changed, 470 insertions(+), 67 deletions(-) create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/AbstractModuleSourcePrototype.java create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveSourceImportNode.java diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/AbstractParser.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/AbstractParser.java index dd132fffffc..fbf1754e4b7 100644 --- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/AbstractParser.java +++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/AbstractParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -384,8 +384,18 @@ protected final void expectDontAdvance(final TokenType expected) throws ParserEx * @return JavaScript value of the token. */ protected final Object getValueNoEscape() { + return getValueNoEscape(token); + } + + /** + * Get the value of a specific token. If the token contains an escape sequence, the method does + * not attempt to convert it. + * + * @return JavaScript value of the token. + */ + protected final Object getValueNoEscape(final long valueToken) { try { - return lexer.getValueOf(token, isStrictMode, false); + return lexer.getValueOf(valueToken, isStrictMode, false); } catch (final ParserException e) { errors.error(e); } diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java index af0eca7781e..3d0df2c80f3 100644 --- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java +++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java @@ -161,6 +161,7 @@ import com.oracle.js.parser.ir.LiteralNode.ArrayLiteralNode; import com.oracle.js.parser.ir.Module; import com.oracle.js.parser.ir.Module.ImportEntry; +import com.oracle.js.parser.ir.Module.ImportPhase; import com.oracle.js.parser.ir.Module.ModuleRequest; import com.oracle.js.parser.ir.NameSpaceImportNode; import com.oracle.js.parser.ir.NamedExportsNode; @@ -203,6 +204,7 @@ public class Parser extends AbstractParser { static final String NEW_TARGET_NAME = "new.target"; static final TruffleString NEW_TARGET_NAME_TS = ParserStrings.constant(NEW_TARGET_NAME); private static final TruffleString IMPORT_META_NAME = ParserStrings.constant("import.meta"); + private static final TruffleString IMPORT_SOURCE_NAME = ParserStrings.constant("import.source"); private static final String PROTOTYPE_NAME = "prototype"; /** Function.prototype.apply method name. */ private static final String APPLY_NAME = "apply"; @@ -254,6 +256,8 @@ public class Parser extends AbstractParser { private static final String GET_SPC = "get "; private static final String SET_SPC = "set "; private static final String META = "meta"; + private static final String SOURCE = "source"; + private static final TruffleString SOURCE_TS = ParserStrings.constant("source"); private static final TruffleString TARGET = ParserStrings.constant("target"); private static final String CONTEXT_ASSIGNMENT_TARGET = "assignment target"; @@ -4844,7 +4848,7 @@ private Expression newExpression(boolean yield, boolean await) { } else { throw error(AbstractParser.message(MSG_EXPECTED_TARGET), token); } - } else if (type == IMPORT && isES2020() && lookahead() == LPAREN) { + } else if (type == IMPORT && lookaheadIsImportCall()) { // new cannot be used with import() throw error(AbstractParser.message(MSG_EXPECTED_OPERAND, IMPORT.getName()), token); } @@ -5080,6 +5084,10 @@ private void verifyPrimaryExpression(Expression lhs, CoverExpressionError coverE * ImportCall: * import ( AssignmentExpression ,opt ) * import ( AssignmentExpression, AssignmentExpression ,opt ) + * import.source ( AssignmentExpression ,opt ) + * import.source ( AssignmentExpression, AssignmentExpression ,opt ) + * ImportMeta: + * import.meta * */ private Expression importExpression(boolean yield, boolean await) { @@ -5098,29 +5106,38 @@ private Expression importExpression(boolean yield, boolean await) { } next(); return new IdentNode(importToken, finish, lexer.stringIntern(IMPORT_META_NAME)).setIsImportMeta(); + } else if (SOURCE.equals(meta) && env.sourcePhaseImports) { + next(); + expectDontAdvance(LPAREN); + return importCall(yield, await, importToken, importStart, importLine, IMPORT_SOURCE_NAME, true); } else { throw error(AbstractParser.message(MSG_UNEXPECTED_IDENT, meta), token); } } else if (type == LPAREN) { + return importCall(yield, await, importToken, importStart, importLine, IMPORT.getNameTS(), false); + } else { + throw error(AbstractParser.message(MSG_EXPECTED_OPERAND, IMPORT.getName()), importToken); + } + } + + private Expression importCall(boolean yield, boolean await, long importToken, int importStart, int importLine, TruffleString importName, boolean sourcePhase) { + assert type == LPAREN; + next(); + List arguments = new ArrayList<>(); + arguments.add(assignmentExpression(true, yield, await)); + if (type == COMMARIGHT && (env.importAttributes || env.importAssertions)) { next(); - List arguments = new ArrayList<>(); - arguments.add(assignmentExpression(true, yield, await)); - if (type == COMMARIGHT && (env.importAttributes || env.importAssertions)) { - next(); - if (type != RPAREN) { - arguments.add(assignmentExpression(true, yield, await)); - if (type == COMMARIGHT) { - next(); - } + if (type != RPAREN) { + arguments.add(assignmentExpression(true, yield, await)); + if (type == COMMARIGHT) { + next(); } } - expect(RPAREN); - - IdentNode importIdent = new IdentNode(importToken, Token.descPosition(importToken) + Token.descLength(importToken), lexer.stringIntern(IMPORT.getNameTS())); - return CallNode.forImport(importLine, importToken, importStart, finish, importIdent, arguments); - } else { - throw error(AbstractParser.message(MSG_EXPECTED_OPERAND, IMPORT.getName()), importToken); } + expect(RPAREN); + + IdentNode importIdent = new IdentNode(importToken, Token.descPosition(importToken) + Token.descLength(importToken), lexer.stringIntern(importName)); + return CallNode.forImport(importLine, importToken, importStart, finish, importIdent, arguments, sourcePhase); } private ArrayList argumentList(boolean yield, boolean await) { @@ -6946,6 +6963,44 @@ private boolean isImportExpression() { return la == PERIOD || la == LPAREN; } + private boolean lookaheadIsImportCall() { + assert type == IMPORT; + if (!isES2020()) { + return false; + } + // import followed by `(` or `.source(` + boolean seenPeriod = false; + boolean seenIdent = false; + for (int i = 1;; i++) { + long currentToken = getToken(k + i); + TokenType t = Token.descType(currentToken); + switch (t) { + case EOL: + case COMMENT: + continue; + case LPAREN: + return !seenPeriod || seenIdent; + case PERIOD: + if (!env.sourcePhaseImports || seenPeriod) { + return false; + } + seenPeriod = true; + continue; + case IDENT: + if (!seenPeriod || seenIdent) { + return false; + } else if (SOURCE_TS.equals(getValueNoEscape(currentToken))) { + seenIdent = true; + continue; + } else { + return false; + } + default: + return false; + } + } + } + private void declareImportBinding(IdentNode ident, boolean star) { Scope moduleScope = lc.getCurrentBlock().getScope(); assert moduleScope.isModuleScope(); @@ -6963,6 +7018,9 @@ private void declareImportStarBinding(IdentNode ident) { declareImportBinding(ident, true); } + /** + * ImportedBinding. + */ private IdentNode importedBindingIdentifier() { return bindingIdentifier(false, isTopLevelAwait(), CONTEXT_IMPORTED_BINDING); } @@ -6974,6 +7032,7 @@ private IdentNode importedBindingIdentifier() { * ImportDeclaration : * import ImportClause FromClause WithClause_opt; * import ModuleSpecifier WithClause_opt; + * import source ImportedBinding FromClause WithClause_opt; * import ImportClause FromClause [no LineTerminator here] AssertClause ; * import ModuleSpecifier [no LineTerminator here] AssertClause ; * ImportClause : @@ -6993,7 +7052,7 @@ private IdentNode importedBindingIdentifier() { private void importDeclaration(ParserContextModuleNode module) { final long importToken = token; expect(IMPORT); - if (type == STRING || type == ESCSTRING) { + end: if (type == STRING || type == ESCSTRING) { // import ModuleSpecifier WithClause_opt; TruffleString moduleSpecifier = (TruffleString) getValue(); long specifierToken = token; @@ -7018,6 +7077,25 @@ private void importDeclaration(ParserContextModuleNode module) { } else if (isBindingIdentifier()) { // ImportedDefaultBinding IdentNode importedDefaultBinding = importedBindingIdentifier(); + + if (env.sourcePhaseImports && SOURCE.equals(importedDefaultBinding.getName()) && isBindingIdentifier() && lookahead() == FROM) { + // import source ImportedBinding FromClause WithClause_opt; + long identToken = token; + IdentNode importedBinding = importedBindingIdentifier(); + declareImportStarBinding(importedBinding); + importClause = new ImportClauseNode(identToken, Token.descPosition(identToken), finish, importedBinding); + + LiteralNode fromClause = fromClause(); + Map attributes = withClause(); + + module.addImport(new ImportNode(importToken, Token.descPosition(importToken), finish, importClause, fromClause, attributes)); + TruffleString moduleSpecifier = fromClause.getValue(); + ModuleRequest moduleRequest = ModuleRequest.create(moduleSpecifier, attributes, ImportPhase.Source); + module.addModuleRequest(moduleRequest); + module.addImportEntry(ImportEntry.importSource(moduleRequest, importedBinding.getNameTS())); + break end; + } + declareImportBinding(importedDefaultBinding); ImportEntry defaultImport = ImportEntry.importDefault(importedDefaultBinding.getNameTS()); importEntries.add(defaultImport); diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ScriptEnvironment.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ScriptEnvironment.java index 17bdb186e63..9605e821209 100644 --- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ScriptEnvironment.java +++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ScriptEnvironment.java @@ -130,6 +130,9 @@ public enum FunctionStatementBehavior { /** Are V8 intrinsics supported? */ final boolean v8Intrinsics; + /** Are source phase imports enabled. */ + final boolean sourcePhaseImports; + public ScriptEnvironment(boolean strict, int ecmaScriptVersion, boolean emptyStatements, @@ -142,6 +145,7 @@ public ScriptEnvironment(boolean strict, boolean classFields, boolean importAttributes, boolean importAssertions, + boolean sourcePhaseImports, boolean privateFieldsIn, boolean topLevelAwait, boolean v8Intrinsics, @@ -159,6 +163,7 @@ public ScriptEnvironment(boolean strict, this.classFields = classFields; this.importAttributes = importAttributes; this.importAssertions = importAssertions; + this.sourcePhaseImports = sourcePhaseImports; this.privateFieldsIn = privateFieldsIn; this.topLevelAwait = topLevelAwait; this.v8Intrinsics = v8Intrinsics; @@ -186,6 +191,7 @@ public static final class Builder { private boolean classFields = true; private boolean importAttributes = false; private boolean importAssertions = false; + private boolean sourcePhaseImports = false; private boolean privateFieldsIn = false; private boolean topLevelAwait = false; private boolean v8Intrinsics = false; @@ -254,6 +260,10 @@ public Builder importAssertions(boolean importAssertions) { return this; } + public void sourcePhaseImports(boolean sourcePhaseImports) { + this.sourcePhaseImports = sourcePhaseImports; + } + public Builder privateFieldsIn(boolean privateFieldsIn) { this.privateFieldsIn = privateFieldsIn; return this; @@ -276,7 +286,7 @@ public Builder functionStatementBehavior(FunctionStatementBehavior functionState public ScriptEnvironment build() { return new ScriptEnvironment(strict, ecmaScriptVersion, emptyStatements, syntaxExtensions, scripting, shebang, constAsVar, allowBigInt, annexB, - classFields, importAttributes, importAssertions, privateFieldsIn, topLevelAwait, v8Intrinsics, functionStatementBehavior); + classFields, importAttributes, importAssertions, sourcePhaseImports, privateFieldsIn, topLevelAwait, v8Intrinsics, functionStatementBehavior); } } } diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/CallNode.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/CallNode.java index c3ff84de3e6..5a989f03116 100644 --- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/CallNode.java +++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/CallNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -81,6 +81,9 @@ public final class CallNode extends OptionalExpression { /** It this a super call in the default derived constructor? */ private static final int IS_DEFAULT_DERIVED_CONSTRUCTOR_SUPER_CALL = 1 << 7; + /** Is this a source phase import call? */ + private static final int IS_IMPORT_SOURCE = 1 << 8; + private final int flags; private final int lineNumber; @@ -116,8 +119,8 @@ private static Expression create(int lineNumber, long token, int start, int fini (isDefaultDerivedConstructorSuperCall ? IS_DEFAULT_DERIVED_CONSTRUCTOR_SUPER_CALL : 0)); } - public static Expression forImport(int lineNumber, long token, int start, int finish, IdentNode importIdent, List args) { - return new CallNode(lineNumber, token, start, finish, importIdent, args, IS_IMPORT); + public static Expression forImport(int lineNumber, long token, int start, int finish, IdentNode importIdent, List args, boolean source) { + return new CallNode(lineNumber, token, start, finish, importIdent, args, IS_IMPORT | (source ? IS_IMPORT_SOURCE : 0)); } private CallNode(int lineNumber, long token, int start, int finish, Expression function, List args, int flags) { @@ -267,6 +270,13 @@ public boolean isImport() { return (flags & IS_IMPORT) != 0; } + /** + * Check if this call is a dynamic import.source call. + */ + public boolean isImportSource() { + return (flags & IS_IMPORT_SOURCE) != 0; + } + /** * Check if this call is an apply call. */ diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/Module.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/Module.java index 78880caf070..dee2cfe5277 100644 --- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/Module.java +++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/Module.java @@ -62,6 +62,7 @@ public final class Module { public static final TruffleString DEFAULT_NAME = ParserStrings.constant("default"); public static final TruffleString STAR_NAME = ParserStrings.constant("\uD800*"); public static final TruffleString NAMESPACE_EXPORT_BINDING_NAME = ParserStrings.constant("\uD800*namespace*"); + public static final TruffleString SOURCE_IMPORT_NAME = ParserStrings.constant("\uD800source"); public static final class ExportEntry { private final TruffleString exportName; @@ -153,6 +154,10 @@ public static ImportEntry importSpecifier(TruffleString importName) { return importSpecifier(importName, importName); } + public static ImportEntry importSource(ModuleRequest moduleRequest, TruffleString localName) { + return new ImportEntry(moduleRequest, SOURCE_IMPORT_NAME, localName); + } + public ImportEntry withFrom(@SuppressWarnings("hiding") ModuleRequest moduleRequest) { return new ImportEntry(moduleRequest, importName, localName); } @@ -175,27 +180,45 @@ public String toString() { } } + public enum ImportPhase { + Evaluation, + Source, + } + public record ModuleRequest( TruffleString specifier, - Map attributes) { + Map attributes, + ImportPhase phase) { + + public static ModuleRequest create(TruffleString specifier, ImportPhase phase) { + return new ModuleRequest(specifier, Collections.emptyMap(), phase); + } public static ModuleRequest create(TruffleString specifier) { - return new ModuleRequest(specifier, Collections.emptyMap()); + return create(specifier, ImportPhase.Evaluation); + } + + public static ModuleRequest create(TruffleString specifier, Map attributes, ImportPhase phase) { + return new ModuleRequest(specifier, Map.copyOf(attributes), phase); } public static ModuleRequest create(TruffleString specifier, Map attributes) { - return new ModuleRequest(specifier, Map.copyOf(attributes)); + return create(specifier, attributes, ImportPhase.Evaluation); + } + + public static ModuleRequest create(TruffleString specifier, Map.Entry[] attributes, ImportPhase phase) { + return new ModuleRequest(specifier, Map.ofEntries(attributes), phase); } public static ModuleRequest create(TruffleString specifier, Map.Entry[] attributes) { - return new ModuleRequest(specifier, Map.ofEntries(attributes)); + return create(specifier, attributes, ImportPhase.Evaluation); } public ModuleRequest withAttributes(Map newAttributes) { if (this.attributes == newAttributes) { return this; } - return new ModuleRequest(specifier, newAttributes); + return new ModuleRequest(specifier, newAttributes, phase); } } diff --git a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java index 2ce302435c4..f4ae206b0d7 100644 --- a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java +++ b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java @@ -60,6 +60,7 @@ import com.oracle.js.parser.ir.Expression; import com.oracle.js.parser.ir.Module; import com.oracle.js.parser.ir.Module.ExportEntry; +import com.oracle.js.parser.ir.Module.ImportPhase; import com.oracle.js.parser.ir.Module.ModuleRequest; import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerAsserts; @@ -493,7 +494,7 @@ public JSPromiseObject loadRequestedModules(JSRealm realm, JSModuleRecord module PromiseCapabilityRecord pc = NewPromiseCapabilityNode.createDefault(realm); GraphLoadingState state = new GraphLoadingState(pc, hostDefined); try { - innerModuleLoading(realm, state, moduleRecord); + innerModuleLoading(realm, state, moduleRecord, true); } catch (AbstractTruffleException e) { assert false : e; // should not throw throw e; @@ -501,17 +502,18 @@ public JSPromiseObject loadRequestedModules(JSRealm realm, JSModuleRecord module return (JSPromiseObject) pc.getPromise(); } - private void innerModuleLoading(JSRealm realm, GraphLoadingState state, AbstractModuleRecord module) { + private void innerModuleLoading(JSRealm realm, GraphLoadingState state, AbstractModuleRecord module, boolean recursiveLoad) { assert state.isLoading; - if (module instanceof JSModuleRecord moduleRecord && moduleRecord.getStatus() == Status.New && + if (recursiveLoad && module instanceof JSModuleRecord moduleRecord && moduleRecord.getStatus() == Status.New && !state.visited.contains(moduleRecord)) { state.visited.add(moduleRecord); int requestedModuleCount = moduleRecord.getModule().getRequestedModules().size(); state.pendingModulesCount += requestedModuleCount; - for (var required : moduleRecord.getModule().getRequestedModules()) { + for (ModuleRequest required : moduleRecord.getModule().getRequestedModules()) { AbstractModuleRecord resolved = moduleRecord.getLoadedModule(realm, required); if (resolved != null) { - innerModuleLoading(realm, state, resolved); + boolean innerRecursiveLoad = required.phase() != ImportPhase.Source; + innerModuleLoading(realm, state, resolved, innerRecursiveLoad); } else { hostLoadImportedModule(realm, moduleRecord, required, state.hostDefined, state); } @@ -563,25 +565,26 @@ private void finishLoadingImportedModule(JSRealm realm, ScriptOrModule referrer, } } if (payload instanceof GraphLoadingState state) { - continueModuleLoading(realm, state, moduleCompletion); + continueModuleLoading(realm, state, moduleRequest.phase(), moduleCompletion); } else { - continueDynamicImport(payload, moduleCompletion); + continueDynamicImport(payload, moduleRequest.phase(), moduleCompletion); } } - private void continueModuleLoading(JSRealm realm, GraphLoadingState state, Completion moduleCompletion) { + private void continueModuleLoading(JSRealm realm, GraphLoadingState state, ImportPhase phase, Completion moduleCompletion) { if (!state.isLoading) { return; } if (moduleCompletion.isNormal()) { - innerModuleLoading(realm, state, (AbstractModuleRecord) moduleCompletion.getValue()); + boolean recursiveLoad = phase != ImportPhase.Source; + innerModuleLoading(realm, state, (AbstractModuleRecord) moduleCompletion.getValue(), recursiveLoad); } else { state.isLoading = false; JSFunction.call(JSArguments.createOneArg(Undefined.instance, state.promiseCapability.getReject(), moduleCompletion.getValue())); } } - private static void continueDynamicImport(Object payload, Completion moduleCompletion) { + private static void continueDynamicImport(Object payload, ImportPhase phase, Completion moduleCompletion) { var continuation = (ImportCallNode.ContinueDynamicImportPayload) payload; PromiseCapabilityRecord promiseCapability = continuation.promiseCapability(); if (moduleCompletion.isAbrupt()) { @@ -590,6 +593,16 @@ private static void continueDynamicImport(Object payload, Completion moduleCompl } AbstractModuleRecord module = (AbstractModuleRecord) moduleCompletion.getValue(); + if (phase == ImportPhase.Source) { + try { + Object moduleSource = module.getModuleSource(); + JSFunction.call(JSArguments.createOneArg(Undefined.instance, promiseCapability.getResolve(), moduleSource)); + } catch (AbstractTruffleException e) { + JSFunction.call(JSArguments.createOneArg(Undefined.instance, promiseCapability.getReject(), getErrorObject(e))); + } + return; + } + // Perform the remaining steps of ContinueDynamicImport. JSFunction.call(JSArguments.create(Undefined.instance, continuation.continueDynamicImportCallback(), promiseCapability, module)); } @@ -634,6 +647,9 @@ private int innerModuleLinking(JSRealm realm, JSModuleRecord moduleRecord, Deque Module module = moduleRecord.getModule(); for (ModuleRequest required : module.getRequestedModules()) { + if (required.phase() != ImportPhase.Evaluation) { + continue; + } JSModuleRecord requiredModule = (JSModuleRecord) moduleRecord.getImportedModule(required); index = innerModuleLinking(realm, requiredModule, stack, index); assert requiredModule.getStatus() == Status.Linking || requiredModule.getStatus() == Status.Linked || @@ -768,6 +784,9 @@ private int innerModuleEvaluation(JSRealm realm, JSModuleRecord moduleRecord, De Module module = moduleRecord.getModule(); for (ModuleRequest required : module.getRequestedModules()) { + if (required.phase() != ImportPhase.Evaluation) { + continue; + } JSModuleRecord requiredModule = (JSModuleRecord) moduleRecord.getImportedModule(required); // Note: Link must have completed successfully prior to invoking this method, // so every requested module is guaranteed to resolve successfully. diff --git a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSParserHelper.java b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSParserHelper.java index 21019e1abd7..7699dc779bd 100644 --- a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSParserHelper.java +++ b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSParserHelper.java @@ -197,6 +197,7 @@ private static ScriptEnvironment makeScriptEnvironment(JSParserOptions parserOpt builder.classFields(parserOptions.classFields()); builder.importAttributes(parserOptions.importAttributes()); builder.importAssertions(parserOptions.importAssertions()); + builder.sourcePhaseImports(parserOptions.sourcePhaseImports()); builder.privateFieldsIn(parserOptions.privateFieldsIn()); builder.topLevelAwait(parserOptions.topLevelAwait()); builder.v8Intrinsics(parserOptions.v8Intrinsics()); diff --git a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSTranslator.java b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSTranslator.java index aaf70c59119..4935a04a28f 100644 --- a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSTranslator.java +++ b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSTranslator.java @@ -78,6 +78,7 @@ import com.oracle.js.parser.ir.LiteralNode; import com.oracle.js.parser.ir.Module; import com.oracle.js.parser.ir.Module.ImportEntry; +import com.oracle.js.parser.ir.Module.ImportPhase; import com.oracle.js.parser.ir.Module.ModuleRequest; import com.oracle.js.parser.ir.ObjectNode; import com.oracle.js.parser.ir.ParameterNode; @@ -1502,9 +1503,12 @@ private void createResolveImports(FunctionNode functionNode, List { + + _toStringTag(0) { + @Override + public Object getKey() { + return Symbol.SYMBOL_TO_STRING_TAG; + } + + @Override + public boolean isGetter() { + return true; + } + }; + + public static final TruffleString ABSTRACT_MODULE_SOURCE_PROTOTYPE = Strings.constant("%AbstractModuleSource%.prototype"); + public static final JSBuiltinsContainer BUILTINS = JSBuiltinsContainer.fromEnum(ABSTRACT_MODULE_SOURCE_PROTOTYPE, AbstractModuleSourcePrototype.class); + + private final int length; + + AbstractModuleSourcePrototype(int length) { + this.length = length; + } + + @Override + public int getLength() { + return length; + } + + @Override + public Object createNode(JSContext context, JSBuiltin builtin, boolean construct, boolean newTarget) { + return switch (this) { + case _toStringTag -> AbstractModuleSourcePrototypeFactory.ToStringTagNodeGen.create(context, builtin, args().withThis().createArgumentNodes(context)); + }; + } + + public abstract static class ToStringTagNode extends JSBuiltinNode { + + public ToStringTagNode(JSContext context, JSBuiltin builtin) { + super(context, builtin); + } + + @SuppressWarnings("unused") + @Specialization + protected static Object doOther(Object thisObj) { + return Undefined.instance; + } + } +} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java index 558909cb77a..73bd32dd175 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java @@ -395,6 +395,7 @@ public enum Constructor implements BuiltinEnum { // --- not new.target-capable below --- TypedArray(0), Symbol(0), + AbstractModuleSource(0), // non-standard (Nashorn) extensions JSAdapter(1), @@ -568,6 +569,7 @@ protected Object createNode(JSContext context, JSBuiltin builtin, boolean constr return ConstructAggregateErrorNodeGen.create(context, builtin, false, args().function().fixedArgs(3).createArgumentNodes(context)); case TypedArray: + case AbstractModuleSource: return AbstractClassConstructorNodeGen.create(context, builtin, args().createArgumentNodes(context)); case Int8Array: case Uint8Array: diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/NodeFactory.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/NodeFactory.java index e8d0e691124..43a575379a5 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/NodeFactory.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/NodeFactory.java @@ -44,6 +44,7 @@ import java.util.Arrays; import java.util.List; +import com.oracle.js.parser.ir.Module.ImportPhase; import com.oracle.js.parser.ir.Module.ModuleRequest; import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.RootCallTarget; @@ -221,6 +222,7 @@ import com.oracle.truffle.js.nodes.module.ImportMetaNode; import com.oracle.truffle.js.nodes.module.ReadImportBindingNode; import com.oracle.truffle.js.nodes.module.ResolveNamedImportNode; +import com.oracle.truffle.js.nodes.module.ResolveSourceImportNode; import com.oracle.truffle.js.nodes.module.ResolveStarImportNode; import com.oracle.truffle.js.nodes.promise.ImportCallNode; import com.oracle.truffle.js.nodes.unary.JSComplementNode; @@ -1275,12 +1277,12 @@ public JavaScriptNode createReadImportBinding(JavaScriptNode readLocal) { return ReadImportBindingNode.create(readLocal); } - public JavaScriptNode createImportCall(JSContext context, JavaScriptNode argument, ScriptOrModule activeScriptOrModule) { - return ImportCallNode.create(context, argument, activeScriptOrModule); + public JavaScriptNode createImportCall(JSContext context, ImportPhase phase, JavaScriptNode argument, JavaScriptNode options, ScriptOrModule activeScriptOrModule) { + return ImportCallNode.create(context, phase, argument, options, activeScriptOrModule); } - public JavaScriptNode createImportCall(JSContext context, JavaScriptNode specifier, ScriptOrModule activeScriptOrModule, JavaScriptNode options) { - return ImportCallNode.createWithOptions(context, specifier, activeScriptOrModule, options); + public JavaScriptNode createResolveSourceImport(JSContext context, JavaScriptNode moduleNode, ModuleRequest moduleRequest, JSWriteFrameSlotNode writeLocalNode) { + return ResolveSourceImportNode.create(context, moduleNode, moduleRequest, writeLocalNode); } public JavaScriptNode createRestObject(JSContext context, JavaScriptNode source, JavaScriptNode excludedNames) { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveSourceImportNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveSourceImportNode.java new file mode 100644 index 00000000000..f8a00a4ff52 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ResolveSourceImportNode.java @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.nodes.module; + +import java.util.Set; + +import com.oracle.js.parser.ir.Module; +import com.oracle.truffle.api.dsl.NeverDefault; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.instrumentation.Tag; +import com.oracle.truffle.js.nodes.JavaScriptNode; +import com.oracle.truffle.js.nodes.access.JSWriteFrameSlotNode; +import com.oracle.truffle.js.nodes.control.StatementNode; +import com.oracle.truffle.js.runtime.JSContext; +import com.oracle.truffle.js.runtime.objects.JSModuleRecord; + +/** + * Resolves a source phase import: gets the imported module's source object, if possible, and + * initializes the local binding (frame slot) with it. + */ +public class ResolveSourceImportNode extends StatementNode { + + private final JSContext context; + private final Module.ModuleRequest moduleRequest; + @Child private JavaScriptNode moduleNode; + @Child private JSWriteFrameSlotNode writeLocalNode; + + ResolveSourceImportNode(JSContext context, JavaScriptNode moduleNode, Module.ModuleRequest moduleRequest, JSWriteFrameSlotNode writeLocalNode) { + this.context = context; + this.moduleRequest = moduleRequest; + this.moduleNode = moduleNode; + this.writeLocalNode = writeLocalNode; + } + + @NeverDefault + public static StatementNode create(JSContext context, JavaScriptNode moduleNode, Module.ModuleRequest moduleRequest, JSWriteFrameSlotNode writeLocalNode) { + return new ResolveSourceImportNode(context, moduleNode, moduleRequest, writeLocalNode); + } + + @Override + public Object execute(VirtualFrame frame) { + JSModuleRecord referencingScriptOrModule = (JSModuleRecord) moduleNode.execute(frame); + var importedModule = referencingScriptOrModule.getImportedModule(moduleRequest); + + var moduleSourceObject = importedModule.getModuleSource(); + // envRec.CreateImmutableBinding(in.[[LocalName]], true). + // Call envRec.InitializeBinding(in.[[LocalName]], moduleSourceObject). + writeLocalNode.executeWrite(frame, moduleSourceObject); + return EMPTY; + } + + @Override + protected JavaScriptNode copyUninitialized(Set> materializedTags) { + return create(context, cloneUninitialized(moduleNode, materializedTags), moduleRequest, cloneUninitialized(writeLocalNode, materializedTags)); + } + +} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java index bf85ba4f7be..a552fad0c4e 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java @@ -43,6 +43,7 @@ import java.util.Map; import java.util.Set; +import com.oracle.js.parser.ir.Module.ImportPhase; import com.oracle.js.parser.ir.Module.ModuleRequest; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -97,6 +98,7 @@ public class ImportCallNode extends JavaScriptNode { private static final HiddenKey LINK_AND_EVALUATE_KEY = new HiddenKey("%linkAndEvaluate"); private static final TruffleString ASSERT = Strings.constant("assert"); + private final ImportPhase phase; @Child private JavaScriptNode argRefNode; private final ScriptOrModule activeScriptOrModule; @Child private NewPromiseCapabilityNode newPromiseCapabilityNode; @@ -113,8 +115,9 @@ public class ImportCallNode extends JavaScriptNode { private final JSContext context; - protected ImportCallNode(JSContext context, JavaScriptNode argRefNode, ScriptOrModule activeScriptOrModule, JavaScriptNode optionsRefNode) { + protected ImportCallNode(JSContext context, ImportPhase phase, JavaScriptNode argRefNode, JavaScriptNode optionsRefNode, ScriptOrModule activeScriptOrModule) { this.context = context; + this.phase = phase; this.argRefNode = argRefNode; this.activeScriptOrModule = activeScriptOrModule; this.optionsRefNode = optionsRefNode; @@ -123,17 +126,14 @@ protected ImportCallNode(JSContext context, JavaScriptNode argRefNode, ScriptOrM this.promiseReactionJobNode = PromiseReactionJobNode.create(context); } - public static ImportCallNode create(JSContext context, JavaScriptNode argRefNode, ScriptOrModule activeScriptOrModule) { - return new ImportCallNode(context, argRefNode, activeScriptOrModule, null); - } - - public static ImportCallNode createWithOptions(JSContext context, JavaScriptNode specifierRefNode, ScriptOrModule activeScriptOrModule, JavaScriptNode optionsRefNode) { - return new ImportCallNode(context, specifierRefNode, activeScriptOrModule, optionsRefNode); + @NeverDefault + public static ImportCallNode create(JSContext context, ImportPhase phase, JavaScriptNode specifierRefNode, JavaScriptNode optionsRefNode, ScriptOrModule activeScriptOrModule) { + return new ImportCallNode(context, phase, specifierRefNode, optionsRefNode, activeScriptOrModule); } @NeverDefault public static ImportCallNode create(JSContext context) { - return create(context, null, null); + return create(context, ImportPhase.Evaluation, null, null, null); } @Override @@ -155,7 +155,7 @@ private Object executeWithoutAttributes(ScriptOrModule referencingScriptOrModule } catch (AbstractTruffleException ex) { return rejectPromise(promiseCapability, ex); } - return hostImportModuleDynamicallyWithSite(referencingScriptOrModule, ModuleRequest.create(specifierString), promiseCapability); + return hostImportModuleDynamicallyWithSite(referencingScriptOrModule, ModuleRequest.create(specifierString, phase), promiseCapability); } @SuppressWarnings("unchecked") @@ -226,7 +226,7 @@ private Object executeAttributes(VirtualFrame frame, ScriptOrModule referencingS } } } - ModuleRequest moduleRequest = attributes == null ? ModuleRequest.create(specifierString) : createModuleRequestWithAttributes(specifierString, attributes); + ModuleRequest moduleRequest = attributes == null ? ModuleRequest.create(specifierString, phase) : createModuleRequestWithAttributes(specifierString, attributes, phase); return hostImportModuleDynamicallyWithSite(referencingScriptOrModule, moduleRequest, promiseCapability); } @@ -241,8 +241,8 @@ private JSDynamicObject hostImportModuleDynamicallyWithSite(ScriptOrModule refer } @TruffleBoundary - private static ModuleRequest createModuleRequestWithAttributes(TruffleString specifierString, Map.Entry[] attributes) { - return ModuleRequest.create(specifierString, attributes); + private static ModuleRequest createModuleRequestWithAttributes(TruffleString specifierString, Map.Entry[] attributes, ImportPhase phase) { + return ModuleRequest.create(specifierString, attributes, phase); } public final JSDynamicObject hostImportModuleDynamically(ScriptOrModule referencingScriptOrModule, ModuleRequest moduleRequest, PromiseCapabilityRecord promiseCapability) { @@ -478,11 +478,6 @@ public Object execute(VirtualFrame frame) { @Override protected JavaScriptNode copyUninitialized(Set> materializedTags) { - if (optionsRefNode == null) { - return ImportCallNode.create(context, cloneUninitialized(argRefNode, materializedTags), activeScriptOrModule); - } else { - return ImportCallNode.createWithOptions(context, cloneUninitialized(argRefNode, materializedTags), activeScriptOrModule, - cloneUninitialized(optionsRefNode, materializedTags)); - } + return ImportCallNode.create(context, phase, cloneUninitialized(argRefNode, materializedTags), cloneUninitialized(optionsRefNode, materializedTags), activeScriptOrModule); } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java index 74322588d49..188e6a5e8f3 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java @@ -648,6 +648,11 @@ public String toString() { public static final OptionKey JSON_MODULES = new OptionKey<>(false); @CompilationFinal private boolean jsonModules; + public static final String SOURCE_PHASE_IMPORTS_NAME = JS_OPTION_PREFIX + "source-phase-imports"; + @Option(name = SOURCE_PHASE_IMPORTS_NAME, category = OptionCategory.USER, help = "Enable source phase imports proposal") // + public static final OptionKey SOURCE_PHASE_IMPORTS = new OptionKey<>(false); + @CompilationFinal private boolean sourcePhaseImports; + public static final String WASM_BIG_INT_NAME = JS_OPTION_PREFIX + "wasm-bigint"; @Option(name = WASM_BIG_INT_NAME, category = OptionCategory.USER, help = "Enable wasm i64 to javascript BigInt support") // public static final OptionKey WASM_BIG_INT = new OptionKey<>(true); @@ -795,6 +800,7 @@ private void cacheOptions(SandboxPolicy sandboxPolicy) { this.importAttributes = readBooleanOption(IMPORT_ATTRIBUTES); this.importAssertions = readBooleanOption(IMPORT_ASSERTIONS); this.jsonModules = readBooleanOption(JSON_MODULES); + this.sourcePhaseImports = readBooleanOption(SOURCE_PHASE_IMPORTS); this.wasmBigInt = readBooleanOption(WASM_BIG_INT); this.esmEvalReturnsExports = readBooleanOption(ESM_EVAL_RETURNS_EXPORTS); this.printNoNewline = readBooleanOption(PRINT_NO_NEWLINE); @@ -1223,6 +1229,10 @@ public boolean isJsonModules() { return jsonModules; } + public boolean isSourcePhaseImports() { + return sourcePhaseImports; + } + public boolean isWasmBigInt() { return wasmBigInt; } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSLanguageOptions.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSLanguageOptions.java index 7cd8e03b4c6..746f357290a 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSLanguageOptions.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSLanguageOptions.java @@ -114,6 +114,7 @@ public record JSLanguageOptions( boolean importAttributes, boolean importAssertions, boolean jsonModules, + boolean sourcePhaseImports, boolean wasmBigInt, boolean esmEvalReturnsExports, boolean isMLEMode, @@ -191,6 +192,7 @@ public static JSLanguageOptions fromContextOptions(JSContextOptions options) { boolean importAttributes = options.isImportAttributes(); boolean importAssertions = options.isImportAssertions(); boolean jsonModules = options.isJsonModules(); + boolean sourcePhaseImports = options.isSourcePhaseImports(); boolean wasmBigInt = options.isWasmBigInt(); boolean esmEvalReturnsExports = options.isEsmEvalReturnsExports(); boolean printNoNewline = options.isPrintNoNewline(); @@ -275,6 +277,7 @@ public static JSLanguageOptions fromContextOptions(JSContextOptions options) { importAttributes, importAssertions, jsonModules, + sourcePhaseImports, wasmBigInt, esmEvalReturnsExports, mleMode, diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSParserOptions.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSParserOptions.java index 35bda03c174..0b80cddce38 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSParserOptions.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSParserOptions.java @@ -60,6 +60,7 @@ public record JSParserOptions(boolean strict, boolean classFields, boolean importAttributes, boolean importAssertions, + boolean sourcePhaseImports, boolean privateFieldsIn, boolean topLevelAwait, boolean v8Intrinsics) { @@ -78,17 +79,18 @@ public static JSParserOptions fromLanguageOptions(JSLanguageOptions options) { boolean classFields = options.classFields(); boolean importAttributes = options.importAttributes(); boolean importAssertions = options.importAssertions(); + boolean sourcePhaseImports = options.sourcePhaseImports(); boolean privateFieldsIn = options.privateFieldsIn(); boolean topLevelAwait = options.topLevelAwait(); boolean v8Intrinsics = options.v8Intrinsics(); return new JSParserOptions(strict, scripting, shebang, ecmaScriptVersion, syntaxExtensions, constAsVar, functionStatementError, emptyStatements, annexB, allowBigInt, - classFields, importAttributes, importAssertions, privateFieldsIn, topLevelAwait, v8Intrinsics); + classFields, importAttributes, importAssertions, sourcePhaseImports, privateFieldsIn, topLevelAwait, v8Intrinsics); } public JSParserOptions withStrict(@SuppressWarnings("hiding") boolean strict) { if (strict != this.strict) { return new JSParserOptions(strict, scripting, shebang, ecmaScriptVersion, syntaxExtensions, constAsVar, functionStatementError, emptyStatements, annexB, allowBigInt, - classFields, importAttributes, importAssertions, privateFieldsIn, topLevelAwait, v8Intrinsics); + classFields, importAttributes, importAssertions, sourcePhaseImports, privateFieldsIn, topLevelAwait, v8Intrinsics); } return this; } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java index d4d288dc75e..9593978e4ee 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java @@ -88,6 +88,7 @@ import com.oracle.truffle.api.profiles.InlinedBranchProfile; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.strings.TruffleString; +import com.oracle.truffle.js.builtins.AbstractModuleSourcePrototype; import com.oracle.truffle.js.builtins.AsyncIteratorHelperPrototypeBuiltins; import com.oracle.truffle.js.builtins.AtomicsBuiltins; import com.oracle.truffle.js.builtins.ConsoleBuiltins; @@ -470,6 +471,9 @@ public class JSRealm { private long staticRegexResultFromIndex; private TruffleString staticRegexResultOriginalInputString; + private final JSFunctionObject abstractModuleSourceConstructor; + private final JSDynamicObject abstractModuleSourcePrototype; + /** WebAssembly support. */ private final Object wasmTableAlloc; private final Object wasmTableGrow; @@ -914,6 +918,10 @@ protected JSRealm(JSContext context, TruffleLanguage.Env env, JSRealm parentReal this.commonJSRequireCache = null; } + ctor = createAbstractModuleSourcePrototype(); + this.abstractModuleSourceConstructor = ctor.getFunctionObject(); + this.abstractModuleSourcePrototype = ctor.getPrototype(); + if (context.getLanguageOptions().webAssembly()) { if (!isWasmAvailable()) { String msg = "WebAssembly API enabled but wasm language cannot be accessed! Did you forget to set the --polyglot flag?"; @@ -2524,6 +2532,23 @@ private JSDynamicObject createForeignIteratorPrototype() { return prototype; } + private JSConstructor createAbstractModuleSourcePrototype() { + JSObject prototype = JSObjectUtil.createOrdinaryPrototypeObject(this); + JSFunctionObject constructor = lookupFunction(ConstructorBuiltins.BUILTINS, ConstructorBuiltins.Constructor.AbstractModuleSource.getKey()); + JSObjectUtil.putDataProperty(constructor, JSObject.PROTOTYPE, prototype, JSAttributes.configurableNotEnumerableNotWritable()); + JSObjectUtil.putConstructorProperty(prototype, constructor); + JSObjectUtil.putAccessorsFromContainer(this, prototype, AbstractModuleSourcePrototype.BUILTINS); + return new JSConstructor(constructor, prototype); + } + + public JSFunctionObject getAbstractModuleSourceConstructor() { + return abstractModuleSourceConstructor; + } + + public JSDynamicObject getAbstractModuleSourcePrototype() { + return abstractModuleSourcePrototype; + } + public JSDynamicObject getArrayProtoValuesIterator() { return arrayProtoValuesIterator; } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/AbstractModuleRecord.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/AbstractModuleRecord.java index f3ad4324c8a..32a94a10229 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/AbstractModuleRecord.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/AbstractModuleRecord.java @@ -95,4 +95,6 @@ public JSDynamicObject getModuleNamespace() { return Undefined.instance; } + public abstract Object getModuleSource(); + } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java index af119fe6ed8..30914e77167 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java @@ -353,6 +353,15 @@ public AbstractModuleRecord getImportedModule(ModuleRequest moduleRequest) { return loadedModules.get(moduleRequest); } + @Override + public Object getModuleSource() { + /* + * Source Text Module Record provides a GetModuleSource implementation that always returns + * an abrupt completion indicating that a source phase import is not available. + */ + throw Errors.createReferenceError("Source phase import is not available for Source Text Module"); + } + @Override public Collection getExportedNames(Set exportStarSet) { CompilerAsserts.neverPartOfCompilation(); From 3d469ff65b33688626b704733c4725c7be982ead Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 13 Aug 2024 13:22:40 +0200 Subject: [PATCH 198/265] Expose AbstractModuleSource constructor to test262. --- .../src/com/oracle/truffle/js/runtime/builtins/JSTest262.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTest262.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTest262.java index bd9e0b93f52..e4889b5dbb9 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTest262.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSTest262.java @@ -53,6 +53,7 @@ public final class JSTest262 { public static final TruffleString CLASS_NAME = Strings.constant("Test262"); public static final TruffleString GLOBAL_PROPERTY_NAME = Strings.constant("$262"); + public static final TruffleString ABSTRACT_MODULE_SOURCE = Strings.constant("AbstractModuleSource"); private JSTest262() { } @@ -66,6 +67,9 @@ public static JSObject create(JSRealm realm) { JSObjectUtil.putDataProperty(obj, Strings.GC, realm.lookupFunction(Test262Builtins.BUILTINS, Strings.GC), JSAttributes.getDefaultNotEnumerable()); JSObject agent = createAgent(realm); JSObjectUtil.putDataProperty(obj, Strings.AGENT, agent, JSAttributes.getDefaultNotEnumerable()); + if (realm.getContextOptions().isSourcePhaseImports()) { + JSObjectUtil.putDataProperty(obj, ABSTRACT_MODULE_SOURCE, realm.getAbstractModuleSourceConstructor(), JSAttributes.getDefaultNotEnumerable()); + } return obj; } From 13f3c59fc79a20264ec994c7e655c240ef09d863 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 13 Aug 2024 03:04:53 +0200 Subject: [PATCH 199/265] Enable test262 feature source-phase-imports. --- .../truffle/js/test/external/test262/Test262Runnable.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java index 53d0fff7c20..ba420c78196 100644 --- a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java +++ b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java @@ -254,6 +254,7 @@ public class Test262Runnable extends TestRunnable { "resizable-arraybuffer", "rest-parameters", "set-methods", + "source-phase-imports", "string-trimming", "super", "symbols-as-weakmap-keys", @@ -270,7 +271,6 @@ public class Test262Runnable extends TestRunnable { "RegExp.escape", "explicit-resource-management", "regexp-modifiers", - "source-phase-imports", "source-phase-imports-module-source", "tail-call-optimization", "uint8array-base64", @@ -334,6 +334,9 @@ public void run() { if (features.contains("set-methods")) { extraOptions.put(JSContextOptions.NEW_SET_METHODS_NAME, "true"); } + if (features.contains("source-phase-imports")) { + extraOptions.put(JSContextOptions.SOURCE_PHASE_IMPORTS_NAME, "true"); + } assert !asyncTest || !negative || negativeExpectedMessage.equals("SyntaxError") : "unsupported async negative test (does not expect an early SyntaxError): " + testFile.getFilePath(); From 4806e385d450d18bccbec8c509cce6ff119606d7 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 13 Aug 2024 17:47:07 +0200 Subject: [PATCH 200/265] Ignore incorrect test262 tests. --- graal-js/test/test262.json | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/graal-js/test/test262.json b/graal-js/test/test262.json index 26dccd3a58a..dd420aae037 100644 --- a/graal-js/test/test262.json +++ b/graal-js/test/test262.json @@ -3664,6 +3664,18 @@ "COMPILE_IMMEDIATELY" : "SKIP" }, "comment" : "Long-running in compile mode" + }, { + "filePath" : "language/module-code/source-phase-import/import-source-binding-name-2.js", + "status" : "FAIL", + "comment" : "Incorrect test (see https://github.com/tc39/test262/issues/4193)" + }, { + "filePath" : "language/module-code/source-phase-import/import-source-binding-name.js", + "status" : "FAIL", + "comment" : "Incorrect test (see https://github.com/tc39/test262/issues/4193)" + }, { + "filePath" : "language/module-code/source-phase-import/import-source-newlines.js", + "status" : "FAIL", + "comment" : "Incorrect test (see https://github.com/tc39/test262/issues/4193)" }, { "filePath" : "language/module-code/top-level-await/syntax/for-await-expr-nested.js", "status" : "PASS", From 27add65253c85f8312b9e75349874e59a7b25177 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 13 Aug 2024 18:02:30 +0200 Subject: [PATCH 201/265] Introduce bare ordinary object shape supplier. --- .../src/com/oracle/truffle/js/runtime/JSContext.java | 4 ++-- .../oracle/truffle/js/runtime/builtins/JSOrdinary.java | 6 ++++++ .../truffle/js/runtime/builtins/intl/JSSegmenter.java | 8 -------- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContext.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContext.java index 1d281a858e1..bf2ec0a44b7 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContext.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContext.java @@ -719,8 +719,8 @@ protected JSContext(Evaluator evaluator, JavaScriptLanguage lang, JSLanguageOpti this.listFormatFactory = builder.create(JSListFormat.INSTANCE); this.relativeTimeFormatFactory = builder.create(JSRelativeTimeFormat.INSTANCE); this.segmenterFactory = builder.create(JSSegmenter.INSTANCE); - this.segmentsFactory = builder.create(JSRealm::getSegmentsPrototype, JSSegmenter::makeInitialSegmentsShape); - this.segmentIteratorFactory = builder.create(JSRealm::getSegmentIteratorPrototype, JSSegmenter::makeInitialSegmentIteratorShape); + this.segmentsFactory = builder.create(JSRealm::getSegmentsPrototype, JSOrdinary.BARE_SHAPE_SUPPLIER); + this.segmentIteratorFactory = builder.create(JSRealm::getSegmentIteratorPrototype, JSOrdinary.BARE_SHAPE_SUPPLIER); this.displayNamesFactory = builder.create(JSDisplayNames.INSTANCE); this.localeFactory = builder.create(JSLocale.INSTANCE); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSOrdinary.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSOrdinary.java index 2e42316a4df..d1fc8f3b0d5 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSOrdinary.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSOrdinary.java @@ -71,6 +71,12 @@ public final class JSOrdinary extends JSNonProxy implements PrototypeSupplier { public static final JSOrdinary INTERNAL_FIELD_INSTANCE = new JSOrdinary(); public static final JSOrdinary OVERLOADED_OPERATORS_INSTANCE = new JSOrdinary(); + /** + * Initial shape for ordinary-like objects, i.e. objects that behave like ordinary objects but + * may not extend {@link JSOrdinaryObject}. + */ + public static final CompilableBiFunction BARE_SHAPE_SUPPLIER = (ctx, proto) -> JSObjectUtil.getProtoChildShape(proto, BARE_INSTANCE, ctx); + private JSOrdinary() { } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/intl/JSSegmenter.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/intl/JSSegmenter.java index 43183898c01..d2c5fd0f725 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/intl/JSSegmenter.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/intl/JSSegmenter.java @@ -284,10 +284,6 @@ public JSDynamicObject getIntrinsicDefaultProto(JSRealm realm) { // Segments Object - public static Shape makeInitialSegmentsShape(JSContext ctx, JSDynamicObject prototype) { - return JSObjectUtil.getProtoChildShape(prototype, JSOrdinary.BARE_INSTANCE, ctx); - } - public static boolean isJSSegments(Object obj) { return obj instanceof JSSegmentsObject; } @@ -300,10 +296,6 @@ public static JSObject createSegmentsPrototype(JSRealm realm) { // Segment Iterator - public static Shape makeInitialSegmentIteratorShape(JSContext ctx, JSDynamicObject prototype) { - return JSObjectUtil.getProtoChildShape(prototype, JSOrdinary.BARE_INSTANCE, ctx); - } - public static boolean isJSSegmentIterator(Object obj) { return obj instanceof JSSegmentIteratorObject; } From c65106b6fab78d3e3f54bd2ab97a64144c5fb3cc Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 13 Aug 2024 18:04:45 +0200 Subject: [PATCH 202/265] Make WebAssembly.Module extend %AbstractModuleSource%. --- .../js/builtins/AbstractModuleSourcePrototype.java | 9 +++++++++ .../src/com/oracle/truffle/js/runtime/JSRealm.java | 7 +++++++ .../oracle/truffle/js/runtime/builtins/JSFunction.java | 4 ++++ .../js/runtime/builtins/wasm/JSWebAssemblyModule.java | 8 +++++++- 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/AbstractModuleSourcePrototype.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/AbstractModuleSourcePrototype.java index 5fc06bc5e5c..408c0999b55 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/AbstractModuleSourcePrototype.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/AbstractModuleSourcePrototype.java @@ -40,6 +40,7 @@ */ package com.oracle.truffle.js.builtins; +import com.oracle.truffle.api.dsl.Fallback; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.nodes.function.JSBuiltin; @@ -48,6 +49,8 @@ import com.oracle.truffle.js.runtime.Strings; import com.oracle.truffle.js.runtime.Symbol; import com.oracle.truffle.js.runtime.builtins.BuiltinEnum; +import com.oracle.truffle.js.runtime.builtins.wasm.JSWebAssemblyModule; +import com.oracle.truffle.js.runtime.builtins.wasm.JSWebAssemblyModuleObject; import com.oracle.truffle.js.runtime.objects.Undefined; /** @@ -96,6 +99,12 @@ public ToStringTagNode(JSContext context, JSBuiltin builtin) { @SuppressWarnings("unused") @Specialization + protected static Object doWasmModule(JSWebAssemblyModuleObject thisObj) { + return JSWebAssemblyModule.WEB_ASSEMBLY_MODULE; + } + + @SuppressWarnings("unused") + @Fallback protected static Object doOther(Object thisObj) { return Undefined.instance; } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java index 9593978e4ee..14f373c9c5a 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java @@ -1238,6 +1238,13 @@ public final JSFunctionObject lookupFunction(JSBuiltinsContainer container, Obje return JSFunction.create(this, functionData); } + public final JSFunctionObject lookupFunctionWithPrototype(JSBuiltinsContainer container, Object key, JSDynamicObject prototype) { + assert JSRuntime.isPropertyKey(key); + Builtin builtin = Objects.requireNonNull(container.lookupFunctionByKey(key)); + JSFunctionData functionData = builtin.createFunctionData(context); + return JSFunction.createWithPrototype(this, functionData, prototype); + } + public final Accessor lookupAccessor(JSBuiltinsContainer container, Object key) { Pair pair = container.lookupAccessorByKey(key); JSBuiltin getterBuiltin = pair.getLeft(); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSFunction.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSFunction.java index 9849675c7f4..efe9a352937 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSFunction.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSFunction.java @@ -261,6 +261,10 @@ public static JSFunctionObject create(JSRealm realm, JSFunctionData functionData return createDefault(functionData, enclosingFrame, CLASS_PROTOTYPE_PLACEHOLDER, realm); } + public static JSFunctionObject createWithPrototype(JSRealm realm, JSFunctionData functionData, JSDynamicObject prototype) { + return createWithPrototype(initialFactory(functionData), realm, functionData, JSFrameUtil.NULL_MATERIALIZED_FRAME, prototype); + } + public static JSFunctionObject createWithPrototype(JSFunctionFactory factory, JSRealm realm, JSFunctionData functionData, MaterializedFrame enclosingFrame, JSDynamicObject prototype) { return createWithPrototype(factory, functionData, enclosingFrame, CLASS_PROTOTYPE_PLACEHOLDER, realm, prototype); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyModule.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyModule.java index e0e3641f945..938878a688c 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyModule.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyModule.java @@ -42,6 +42,7 @@ import com.oracle.truffle.api.object.Shape; import com.oracle.truffle.api.strings.TruffleString; +import com.oracle.truffle.js.builtins.ConstructorBuiltins; import com.oracle.truffle.js.builtins.wasm.WebAssemblyModuleFunctionBuiltins; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRealm; @@ -75,7 +76,7 @@ public static boolean isJSWebAssemblyModule(Object object) { @Override public JSDynamicObject createPrototype(JSRealm realm, JSFunctionObject constructor) { - JSObject prototype = JSObjectUtil.createOrdinaryPrototypeObject(realm); + JSObject prototype = JSObjectUtil.createOrdinaryPrototypeObject(realm, realm.getAbstractModuleSourcePrototype()); JSObjectUtil.putConstructorProperty(prototype, constructor); JSObjectUtil.putToStringTag(prototype, WEB_ASSEMBLY_MODULE); return prototype; @@ -91,6 +92,11 @@ public Shape makeInitialShape(JSContext ctx, JSDynamicObject prototype) { return JSObjectUtil.getProtoChildShape(prototype, INSTANCE, ctx); } + @Override + public JSFunctionObject createConstructorObject(JSRealm realm) { + return realm.lookupFunctionWithPrototype(ConstructorBuiltins.BUILTINS, getClassName(), realm.getAbstractModuleSourceConstructor()); + } + public static JSConstructor createConstructor(JSRealm realm) { return INSTANCE.createConstructorAndPrototype(realm, WebAssemblyModuleFunctionBuiltins.BUILTINS); } From f23b8bb4d98eeca0a41ab4bdd558d8f1f4fa9a71 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 14 Aug 2024 03:01:40 +0200 Subject: [PATCH 203/265] Ignore spurious testv8 failure. --- graal-js/test/testV8.json | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/graal-js/test/testV8.json b/graal-js/test/testV8.json index 65a526d3266..00c6c9cf79c 100644 --- a/graal-js/test/testV8.json +++ b/graal-js/test/testV8.json @@ -726,6 +726,10 @@ "filePath" : "mjsunit/harmony/generators.js", "status" : "SKIP", "comment" : "non-standard do-expressions" + }, { + "filePath" : "mjsunit/harmony/import-from-compilation-errored.js", + "status" : "FAIL", + "comment" : "only fails because of different line number in error stack" }, { "filePath" : "mjsunit/harmony/private-accessors.js", "status" : "FAIL", From 41b127ae8ed6a13f9d92324f45d35bc1298d66db Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 13 Aug 2024 20:22:12 +0200 Subject: [PATCH 204/265] Add experimental support for source phase wasm module imports. --- .../truffle/js/parser/GraalJSEvaluator.java | 19 ++- .../truffle/js/lang/JavaScriptLanguage.java | 5 + .../oracle/truffle/js/runtime/Evaluator.java | 3 + .../oracle/truffle/js/runtime/JSRealm.java | 4 + .../objects/DefaultESModuleLoader.java | 118 ++++++++++++++---- .../objects/WebAssemblyModuleRecord.java | 97 ++++++++++++++ 6 files changed, 218 insertions(+), 28 deletions(-) create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/WebAssemblyModuleRecord.java diff --git a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java index f4ae206b0d7..28ebd331d72 100644 --- a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java +++ b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java @@ -40,8 +40,11 @@ */ package com.oracle.truffle.js.parser; +import static com.oracle.truffle.js.lang.JavaScriptLanguage.JSON_MIME_TYPE; +import static com.oracle.truffle.js.lang.JavaScriptLanguage.JSON_SOURCE_NAME_SUFFIX; import static com.oracle.truffle.js.lang.JavaScriptLanguage.MODULE_MIME_TYPE; import static com.oracle.truffle.js.lang.JavaScriptLanguage.MODULE_SOURCE_NAME_SUFFIX; +import static com.oracle.truffle.js.lang.JavaScriptLanguage.WASM_MIME_TYPE; import java.nio.ByteBuffer; import java.util.ArrayDeque; @@ -53,6 +56,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.TreeSet; import java.util.function.Supplier; @@ -109,10 +113,12 @@ import com.oracle.truffle.js.runtime.JSRuntime; import com.oracle.truffle.js.runtime.JavaScriptRootNode; import com.oracle.truffle.js.runtime.Strings; +import com.oracle.truffle.js.runtime.builtins.JSArrayBuffer; import com.oracle.truffle.js.runtime.builtins.JSFunction; import com.oracle.truffle.js.runtime.builtins.JSFunctionData; import com.oracle.truffle.js.runtime.builtins.JSFunctionObject; import com.oracle.truffle.js.runtime.builtins.JSPromiseObject; +import com.oracle.truffle.js.runtime.builtins.wasm.JSWebAssemblyModuleObject; import com.oracle.truffle.js.runtime.objects.AbstractModuleRecord; import com.oracle.truffle.js.runtime.objects.Completion; import com.oracle.truffle.js.runtime.objects.ExportResolution; @@ -126,6 +132,7 @@ import com.oracle.truffle.js.runtime.objects.PromiseCapabilityRecord; import com.oracle.truffle.js.runtime.objects.ScriptOrModule; import com.oracle.truffle.js.runtime.objects.Undefined; +import com.oracle.truffle.js.runtime.objects.WebAssemblyModuleRecord; /** * This is the main external entry into the GraalJS parser. @@ -410,10 +417,20 @@ public JSModuleData envParseModule(JSRealm realm, Source source) { return moduleScriptRoot.getModuleData(); } + @TruffleBoundary + @Override + public AbstractModuleRecord parseWasmModuleSource(JSRealm realm, Source source) { + assert WASM_MIME_TYPE.equals(source.getMimeType()) : source; + JSFunctionObject webAssemblyModuleConstructor = Objects.requireNonNull(realm.getWebAssemblyModuleConstructor(), "WebAssembly.Module"); + JSWebAssemblyModuleObject wasmModule = (JSWebAssemblyModuleObject) JSFunction.construct(webAssemblyModuleConstructor, + new Object[]{JSArrayBuffer.createArrayBuffer(realm.getContext(), realm, source.getBytes().toByteArray())}); + return new WebAssemblyModuleRecord(realm.getContext(), source, wasmModule); + } + @TruffleBoundary @Override public JSModuleRecord parseJSONModule(JSRealm realm, Source source) { - assert isModuleSource(source) : source; + assert JSON_MIME_TYPE.equals(source.getMimeType()) || (source.getMimeType() == null && source.getName().endsWith(JSON_SOURCE_NAME_SUFFIX)) : source; Object json = JSFunction.call(JSArguments.createOneArg(Undefined.instance, realm.getJsonParseFunctionObject(), Strings.fromJavaString(source.getCharacters().toString()))); return createSyntheticJSONModule(realm, source, json); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/lang/JavaScriptLanguage.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/lang/JavaScriptLanguage.java index bf646c34112..61bbe6d56ad 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/lang/JavaScriptLanguage.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/lang/JavaScriptLanguage.java @@ -166,6 +166,11 @@ public final class JavaScriptLanguage extends TruffleLanguage { public static final String SCRIPT_SOURCE_NAME_SUFFIX = ".js"; public static final String MODULE_SOURCE_NAME_SUFFIX = ".mjs"; public static final String JSON_SOURCE_NAME_SUFFIX = ".json"; + + public static final String WASM_LANGUAGE_ID = "wasm"; + public static final String WASM_MIME_TYPE = "application/wasm"; + public static final String WASM_SOURCE_NAME_SUFFIX = ".wasm"; + public static final String INTERNAL_SOURCE_URL_PREFIX = "internal:"; public static final String NODE_ENV_PARSE_TOKEN = "%NODE_ENV_PARSE_TOKEN%"; diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java index e3411d10f43..3ed3fa4adcd 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java @@ -51,6 +51,7 @@ import com.oracle.truffle.js.nodes.JavaScriptNode; import com.oracle.truffle.js.nodes.ScriptNode; import com.oracle.truffle.js.runtime.builtins.JSPromiseObject; +import com.oracle.truffle.js.runtime.objects.AbstractModuleRecord; import com.oracle.truffle.js.runtime.objects.JSModuleData; import com.oracle.truffle.js.runtime.objects.JSModuleRecord; import com.oracle.truffle.js.runtime.objects.ScriptOrModule; @@ -99,6 +100,8 @@ public interface Evaluator { */ JSModuleData envParseModule(JSRealm realm, Source source); + AbstractModuleRecord parseWasmModuleSource(JSRealm realm, Source source); + JSModuleRecord parseJSONModule(JSRealm realm, Source source); void hostLoadImportedModule(JSRealm realm, ScriptOrModule referrer, Module.ModuleRequest moduleRequest, Object hostDefined, Object payload); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java index 14f373c9c5a..e9c7ec13b20 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java @@ -3295,6 +3295,10 @@ public Object getWasmRefNull() { return wasmRefNull; } + public JSFunctionObject getWebAssemblyModuleConstructor() { + return webAssemblyModuleConstructor; + } + public JSDynamicObject getWebAssemblyModulePrototype() { return webAssemblyModulePrototype; } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java index bd717cf9bfa..331f57aafca 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java @@ -49,6 +49,7 @@ import java.util.HashMap; import java.util.Map; +import com.oracle.js.parser.ir.Module.ImportPhase; import com.oracle.js.parser.ir.Module.ModuleRequest; import com.oracle.truffle.api.TruffleFile; import com.oracle.truffle.api.TruffleLanguage; @@ -68,9 +69,6 @@ public class DefaultESModuleLoader implements JSModuleLoader { public static final String DOT_SLASH = "./"; public static final String DOT_DOT_SLASH = "../"; - private static final int JS_MODULE_TYPE = 1 << 0; - private static final int JSON_MODULE_TYPE = 1 << 1; - protected final JSRealm realm; protected final Map moduleMap = new HashMap<>(); @@ -165,6 +163,12 @@ private JSException createErrorFromFileSystemException(FileSystemException fsex, message = "Cannot access module"; } } + message = buildErrorMessage(message, fileName, refPath, reason); + return Errors.createError(message, fsex); + } + + private static String buildErrorMessage(String causeMessage, String fileName, String refPath, String reason) { + String message = causeMessage; if (message == null) { message = "Error reading module"; } @@ -173,9 +177,15 @@ private JSException createErrorFromFileSystemException(FileSystemException fsex, message += " imported from " + refPath; } if (reason != null) { - message = ": " + reason; + message += ": " + reason; } - return Errors.createError(message, fsex); + return message; + } + + private static JSException createErrorUnsupportedPhase(ScriptOrModule referrer, ModuleRequest moduleRequest) { + String refPath = referrer != null ? referrer.getSource().getName() : null; + return Errors.createError(buildErrorMessage(null, moduleRequest.specifier().toJavaStringUncached(), refPath, + moduleRequest.phase() + " phase imports not supported for this type of module")); } private boolean bareSpecifierDirectLookup(String specifier) { @@ -205,20 +215,30 @@ protected AbstractModuleRecord loadModuleFromUrl(ScriptOrModule referrer, Module return existingModule; } - Source source = Source.newBuilder(JavaScriptLanguage.ID, moduleFile).name(Strings.toJavaString(moduleRequest.specifier())).mimeType(JavaScriptLanguage.MODULE_MIME_TYPE).build(); + String mimeType = findMimeType(moduleFile); + String language = findLanguage(mimeType); + + Source source = Source.newBuilder(language, moduleFile).name(Strings.toJavaString(moduleRequest.specifier())).mimeType(mimeType).build(); Map attributes = moduleRequest.attributes(); - int moduleType = getModuleType(moduleFile.getName()); TruffleString assertedType = attributes.get(JSContext.getTypeImportAttribute()); - if (!doesModuleTypeMatchAssertionType(assertedType, moduleType)) { + if (!doesModuleTypeMatchAssertionType(assertedType, mimeType)) { throw Errors.createTypeError("Invalid module type was asserted"); } - JSModuleRecord newModule; - if (isModuleType(moduleType, JSON_MODULE_TYPE)) { - newModule = realm.getContext().getEvaluator().parseJSONModule(realm, source); - } else { - JSModuleData parsedModule = realm.getContext().getEvaluator().envParseModule(realm, source); - newModule = new JSModuleRecord(parsedModule, this); - } + AbstractModuleRecord newModule = switch (mimeType) { + case JavaScriptLanguage.JSON_MIME_TYPE -> realm.getContext().getEvaluator().parseJSONModule(realm, source); + case JavaScriptLanguage.WASM_MIME_TYPE -> { + if (moduleRequest.phase() == ImportPhase.Source && realm.getContextOptions().isWebAssembly()) { + yield realm.getContext().getEvaluator().parseWasmModuleSource(realm, source); + } else { + throw createErrorUnsupportedPhase(referrer, moduleRequest); + } + } + default -> { + JSModuleData parsedModule = realm.getContext().getEvaluator().envParseModule(realm, source); + yield new JSModuleRecord(parsedModule, this); + } + }; + moduleMap.put(canonicalPath, newModule); if (referrer != null) { @@ -227,25 +247,69 @@ protected AbstractModuleRecord loadModuleFromUrl(ScriptOrModule referrer, Module return newModule; } - private static boolean doesModuleTypeMatchAssertionType(TruffleString assertedType, int moduleType) { - if (assertedType == null) { - return true; + /** + * Try to detect the mime type of the imported module, considering only supported mime types, + * and assuming ES module by default. + */ + private String findMimeType(TruffleFile moduleFile) { + final String defaultMimeType = JavaScriptLanguage.MODULE_MIME_TYPE; + if (moduleFile == null) { + return defaultMimeType; } - if (Strings.equals(Strings.JSON, assertedType)) { - return isModuleType(moduleType, JSON_MODULE_TYPE); + String foundMimeType; + try { + // Source.findMimeType may return null. + foundMimeType = Source.findMimeType(moduleFile); + } catch (IOException | SecurityException e) { + foundMimeType = null; } - return false; + if (foundMimeType == null) { + foundMimeType = findMimeTypeFromExtension(moduleFile.getName()); + } + return filterSupportedMimeType(foundMimeType, defaultMimeType); } - private int getModuleType(String moduleName) { - if (realm.getContext().getLanguageOptions().jsonModules() && moduleName.endsWith(JavaScriptLanguage.JSON_SOURCE_NAME_SUFFIX)) { - return JSON_MODULE_TYPE; + private String filterSupportedMimeType(String foundMimeType, String defaultMimeType) { + String mimeType = defaultMimeType; + if (JavaScriptLanguage.JSON_MIME_TYPE.equals(foundMimeType)) { + if (realm.getContextOptions().isJsonModules()) { + mimeType = JavaScriptLanguage.JSON_MIME_TYPE; + } + } else if (JavaScriptLanguage.WASM_MIME_TYPE.equals(foundMimeType)) { + mimeType = JavaScriptLanguage.WASM_MIME_TYPE; } - return JS_MODULE_TYPE; + return mimeType; } - private static boolean isModuleType(int moduleType, int expectedType) { - return (moduleType & expectedType) != 0; + private static String findMimeTypeFromExtension(String moduleName) { + if (moduleName.endsWith(JavaScriptLanguage.JSON_SOURCE_NAME_SUFFIX)) { + return JavaScriptLanguage.JSON_MIME_TYPE; + } + if (moduleName.endsWith(JavaScriptLanguage.WASM_SOURCE_NAME_SUFFIX)) { + return JavaScriptLanguage.WASM_MIME_TYPE; + } + return null; + } + + /** + * Like {@link Source#findLanguage(String)}, but considering only supported mime types. + */ + private static String findLanguage(String mimeType) { + String language = JavaScriptLanguage.ID; + if (JavaScriptLanguage.WASM_MIME_TYPE.equals(mimeType)) { + language = JavaScriptLanguage.WASM_LANGUAGE_ID; + } + return language; + } + + private static boolean doesModuleTypeMatchAssertionType(TruffleString assertedType, String mimeType) { + if (assertedType == null) { + return true; + } + if (Strings.equals(Strings.JSON, assertedType)) { + return mimeType.equals(JavaScriptLanguage.JSON_MIME_TYPE); + } + return false; } @Override diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/WebAssemblyModuleRecord.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/WebAssemblyModuleRecord.java new file mode 100644 index 00000000000..cb47c2caa52 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/WebAssemblyModuleRecord.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.runtime.objects; + +import java.util.Collection; +import java.util.Set; + +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.strings.TruffleString; +import com.oracle.truffle.js.runtime.Errors; +import com.oracle.truffle.js.runtime.JSContext; +import com.oracle.truffle.js.runtime.JSRealm; +import com.oracle.truffle.js.runtime.builtins.JSPromiseObject; +import com.oracle.truffle.js.runtime.builtins.wasm.JSWebAssemblyModuleObject; +import com.oracle.truffle.js.runtime.util.Pair; + +/** + * WebAssembly Module Record. + */ +public class WebAssemblyModuleRecord extends AbstractModuleRecord { + + private final JSWebAssemblyModuleObject webAssemblyModule; + + public WebAssemblyModuleRecord(JSContext context, Source source, JSWebAssemblyModuleObject webAssemblyModule) { + super(context, source); + this.webAssemblyModule = webAssemblyModule; + } + + @Override + public Object getModuleSource() { + return webAssemblyModule; + } + + @Override + public JSPromiseObject loadRequestedModules(JSRealm realm, Object hostDefined) { + throw Errors.createSyntaxError("Unsupported"); + } + + @Override + public void link(JSRealm realm) { + throw Errors.createSyntaxError("Unsupported"); + } + + @Override + public Object evaluate(JSRealm realm) { + throw Errors.createSyntaxError("Unsupported"); + } + + @Override + public Collection getExportedNames(Set exportStarSet) { + throw Errors.createSyntaxError("Unsupported"); + } + + @Override + public ExportResolution resolveExport(TruffleString exportName, Set> resolveSet) { + throw Errors.createSyntaxError("Unsupported"); + } + +} From be04aa6ef2e3db70547da10844ebe45d82b98425 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 14 Aug 2024 06:09:19 +0200 Subject: [PATCH 205/265] Implement *ModuleRecord.toString(). --- .../oracle/truffle/js/runtime/objects/JSModuleRecord.java | 6 ++++++ .../truffle/js/runtime/objects/WebAssemblyModuleRecord.java | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java index 30914e77167..f736ad1414c 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java @@ -506,4 +506,10 @@ public void rememberImportedModuleSource(TruffleString moduleSpecifier, Source m parsedModule.rememberImportedModuleSource(moduleSpecifier, moduleSource); } + @Override + public String toString() { + CompilerAsserts.neverPartOfCompilation(); + return "SourceTextModule" + "@" + Integer.toHexString(System.identityHashCode(this)) + "[status=" + getStatus() + ", source=" + getSource() + "]"; + } + } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/WebAssemblyModuleRecord.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/WebAssemblyModuleRecord.java index cb47c2caa52..a5f62c0ddc4 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/WebAssemblyModuleRecord.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/WebAssemblyModuleRecord.java @@ -43,6 +43,7 @@ import java.util.Collection; import java.util.Set; +import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.runtime.Errors; @@ -94,4 +95,9 @@ public ExportResolution resolveExport(TruffleString exportName, Set Date: Wed, 14 Aug 2024 18:15:03 +0200 Subject: [PATCH 206/265] Test262: Provide "" and enable source-phase-imports-module-source feature. --- .../external/suite/ForwardingFileSystem.java | 182 ++++++++++++++++++ .../js/test/external/suite/TestCallable.java | 14 +- .../external/test262/Test262Runnable.java | 53 ++++- 3 files changed, 241 insertions(+), 8 deletions(-) create mode 100644 graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/suite/ForwardingFileSystem.java diff --git a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/suite/ForwardingFileSystem.java b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/suite/ForwardingFileSystem.java new file mode 100644 index 00000000000..103340490fe --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/suite/ForwardingFileSystem.java @@ -0,0 +1,182 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.test.external.suite; + +import java.io.IOException; +import java.net.URI; +import java.nio.channels.SeekableByteChannel; +import java.nio.charset.Charset; +import java.nio.file.AccessMode; +import java.nio.file.CopyOption; +import java.nio.file.DirectoryStream; +import java.nio.file.LinkOption; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.attribute.FileAttribute; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +import org.graalvm.polyglot.io.FileSystem; + +public class ForwardingFileSystem implements FileSystem { + + private final FileSystem delegate; + + protected ForwardingFileSystem() { + this(FileSystem.newDefaultFileSystem()); + } + + protected ForwardingFileSystem(FileSystem fileSystem) { + Objects.requireNonNull(fileSystem, "FileSystem must be non null."); + this.delegate = fileSystem; + } + + @Override + public Path parsePath(URI path) { + return delegate.parsePath(path); + } + + @Override + public Path parsePath(String path) { + return delegate.parsePath(path); + } + + @Override + public void checkAccess(Path path, Set modes, LinkOption... linkOptions) throws IOException { + delegate.checkAccess(path, modes, linkOptions); + } + + @Override + public void createDirectory(Path dir, FileAttribute... attrs) throws IOException { + delegate.createDirectory(dir, attrs); + } + + @Override + public void delete(Path path) throws IOException { + delegate.delete(path); + } + + @Override + public void createLink(Path link, Path existing) throws IOException { + delegate.createLink(link, existing); + } + + @Override + public void createSymbolicLink(Path link, Path target, FileAttribute... attrs) throws IOException { + delegate.createSymbolicLink(link, target, attrs); + } + + @Override + public Path readSymbolicLink(Path link) throws IOException { + return delegate.readSymbolicLink(link); + } + + @Override + public void copy(Path source, Path target, CopyOption... options) throws IOException { + delegate.copy(source, target, options); + } + + @Override + public void move(Path source, Path target, CopyOption... options) throws IOException { + delegate.move(source, target, options); + } + + @Override + public SeekableByteChannel newByteChannel(Path path, Set options, FileAttribute... attrs) throws IOException { + return delegate.newByteChannel(path, options, attrs); + } + + @Override + public DirectoryStream newDirectoryStream(Path dir, DirectoryStream.Filter filter) throws IOException { + return delegate.newDirectoryStream(dir, filter); + } + + @Override + public Map readAttributes(Path path, String attributes, LinkOption... options) throws IOException { + return delegate.readAttributes(path, attributes, options); + } + + @Override + public void setAttribute(Path path, String attribute, Object value, LinkOption... options) throws IOException { + delegate.setAttribute(path, attribute, value, options); + } + + @Override + public Path toAbsolutePath(Path path) { + return delegate.toAbsolutePath(path); + } + + @Override + public Path toRealPath(Path path, LinkOption... linkOptions) throws IOException { + return delegate.toRealPath(path, linkOptions); + } + + @Override + public void setCurrentWorkingDirectory(Path currentWorkingDirectory) { + delegate.setCurrentWorkingDirectory(currentWorkingDirectory); + } + + @Override + public String getSeparator() { + return delegate.getSeparator(); + } + + @Override + public String getMimeType(Path path) { + return delegate.getMimeType(path); + } + + @Override + public Charset getEncoding(Path path) { + return delegate.getEncoding(path); + } + + @Override + public Path getTempDirectory() { + return delegate.getTempDirectory(); + } + + @Override + public boolean isSameFile(Path path1, Path path2, LinkOption... options) throws IOException { + return delegate.isSameFile(path1, path2, options); + } +} diff --git a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/suite/TestCallable.java b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/suite/TestCallable.java index 0e925b49791..d0f27526e64 100644 --- a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/suite/TestCallable.java +++ b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/suite/TestCallable.java @@ -42,7 +42,6 @@ import java.io.File; import java.io.OutputStream; -import java.util.Collections; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -64,23 +63,26 @@ public class TestCallable extends AbstractTestCallable { protected final Context.Builder contextBuilder; public TestCallable(TestSuite suite, Source[] prequelSources, Source testSource, File scriptFile, int ecmaScriptVersion) { - this(suite, prequelSources, testSource, scriptFile, ecmaScriptVersion, Collections.emptyMap()); + this(suite, prequelSources, testSource, scriptFile, ecmaScriptVersion, Map.of()); } - @SuppressWarnings("this-escape") public TestCallable(TestSuite suite, Source[] prequelSources, Source testSource, File scriptFile, int ecmaScriptVersion, Map extraOptions) { + this(suite, prequelSources, testSource, scriptFile, ecmaScriptVersion, extraOptions, IOAccess.newBuilder().allowHostFileAccess(true).build()); + } + + public TestCallable(TestSuite suite, Source[] prequelSources, Source testSource, File scriptFile, int ecmaScriptVersion, Map extraOptions, IOAccess ioAccess) { super(suite); this.prequelSources = prequelSources; this.testSource = testSource; this.scriptFile = scriptFile; - if (getConfig().isPolyglot()) { + if (suite.getConfig().isPolyglot()) { this.contextBuilder = Context.newBuilder(); contextBuilder.allowPolyglotAccess(PolyglotAccess.ALL); } else { this.contextBuilder = Context.newBuilder(JavaScriptLanguage.ID); } - contextBuilder.allowIO(IOAccess.newBuilder().allowHostFileAccess(true).build()); + contextBuilder.allowIO(ioAccess); contextBuilder.allowExperimentalOptions(true); contextBuilder.allowCreateThread(true); contextBuilder.option(JSContextOptions.ECMASCRIPT_VERSION_NAME, ecmaScriptVersionToOptionString(ecmaScriptVersion)); @@ -89,7 +91,7 @@ public TestCallable(TestSuite suite, Source[] prequelSources, Source testSource, contextBuilder.options(extraOptions); contextBuilder.option(JSContextOptions.LOCALE_NAME, suite.getConfig().getLocale()); contextBuilder.timeZone(suite.getConfig().getTimeZone()); - if (getConfig().isShareEngine()) { + if (suite.getConfig().isShareEngine()) { contextBuilder.engine(suite.getSharedEngine()); } else { contextBuilder.option("engine.WarnInterpreterOnly", Boolean.toString(false)); diff --git a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java index ba420c78196..30b2d8fcf27 100644 --- a/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java +++ b/graal-js/src/com.oracle.truffle.js.test.external/src/com/oracle/truffle/js/test/external/test262/Test262Runnable.java @@ -42,9 +42,15 @@ import static com.oracle.truffle.js.lang.JavaScriptLanguage.MODULE_MIME_TYPE; +import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.IOException; import java.io.OutputStream; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -60,9 +66,11 @@ import org.graalvm.polyglot.PolyglotException; import org.graalvm.polyglot.Source; +import org.graalvm.polyglot.io.IOAccess; import com.oracle.truffle.js.runtime.JSConfig; import com.oracle.truffle.js.runtime.JSContextOptions; +import com.oracle.truffle.js.test.external.suite.ForwardingFileSystem; import com.oracle.truffle.js.test.external.suite.TestCallable; import com.oracle.truffle.js.test.external.suite.TestExtProcessCallable; import com.oracle.truffle.js.test.external.suite.TestFile; @@ -255,6 +263,7 @@ public class Test262Runnable extends TestRunnable { "rest-parameters", "set-methods", "source-phase-imports", + "source-phase-imports-module-source", "string-trimming", "super", "symbols-as-weakmap-keys", @@ -271,7 +280,6 @@ public class Test262Runnable extends TestRunnable { "RegExp.escape", "explicit-resource-management", "regexp-modifiers", - "source-phase-imports-module-source", "tail-call-optimization", "uint8array-base64", }); @@ -378,6 +386,18 @@ public void run() { } } + if (features.contains("source-phase-imports-module-source")) { + assert features.contains("source-phase-imports") : "feature source-phase-imports-module-source requires source-phase-imports"; + extraOptions.put(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw"); + // "" is provided by a WebAssembly.Module via polyglot FileSystem. + if (getConfig().isPolyglot() && !getConfig().isExtLauncher()) { + // enable webassembly, so that we can compile the dummy module source + extraOptions.put(JSContextOptions.WEBASSEMBLY_NAME, "true"); + } else { + supported = false; + } + } + TestFile.EcmaVersion ecmaVersion = testFile.getEcmaVersion(); if (ecmaVersion == null) { ecmaVersion = TestFile.EcmaVersion.forVersions(featureVersion); @@ -424,7 +444,8 @@ private TestFile.Result runInJVM(int ecmaVersion, File file, Source testSource, Map extraOptions, OutputStream byteArrayOutputStream, OutputStream outputStream) { Future future = null; try { - TestCallable tc = new TestCallable(suite, harnessSources, testSource, file, ecmaVersion, extraOptions); + IOAccess ioAccess = IOAccess.newBuilder().fileSystem(new ModuleSourceFS()).build(); + TestCallable tc = new TestCallable(suite, harnessSources, testSource, file, ecmaVersion, extraOptions, ioAccess); tc.setOutput(outputStream); tc.setError(outputStream); if (suite.executeWithSeparateThreads() && getConfig().isUseThreads()) { @@ -599,4 +620,32 @@ private static Set getFeatures(List scriptCode) { return getStrings(scriptCode, FEATURES_PREFIX, FEATURES_PATTERN, SPLIT_PATTERN).collect(Collectors.toSet()); } + private static final class ModuleSourceFS extends ForwardingFileSystem { + private static final String MODULE_SOURCE_SPECIFIER = ""; + private static final byte[] MINIMAL_WASM_MODULE_BYTES = {0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00}; + + @Override + public Path parsePath(String path) { + // Replace "" with an actual existing path. + if (MODULE_SOURCE_SPECIFIER.equals(path)) { + return LazyTempFile.minimalWasmModulePath; + } + return super.parsePath(path); + } + + private static final class LazyTempFile { + private static Path minimalWasmModulePath; + + static { + try { + File tmpFile = File.createTempFile("minimal", ".wasm"); + tmpFile.deleteOnExit(); + Files.copy(new ByteArrayInputStream(MINIMAL_WASM_MODULE_BYTES), tmpFile.toPath(), StandardCopyOption.REPLACE_EXISTING); + minimalWasmModulePath = tmpFile.toPath(); + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + } + } + } } From ad0bad01e9a3b488da3ec333ab9dff6b45c10c61 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 19 Aug 2024 15:43:34 +0200 Subject: [PATCH 207/265] Fix hangs with top-level await. --- .../oracle/truffle/js/parser/GraalJSEvaluator.java | 14 ++++++++++++++ .../truffle/js/runtime/objects/JSModuleRecord.java | 10 ++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java index 28ebd331d72..73b6d7f3faa 100644 --- a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java +++ b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java @@ -827,7 +827,12 @@ private int innerModuleEvaluation(JSRealm realm, JSModuleRecord moduleRecord, De } if (moduleRecord.getPendingAsyncDependencies() > 0 || moduleRecord.hasTLA()) { assert !moduleRecord.isAsyncEvaluation(); + moduleRecord.setAsyncEvaluation(true); moduleRecord.setAsyncEvaluatingOrder(realm.nextAsyncEvaluationOrder()); + /* + * NOTE: The order in which module records have their [[AsyncEvaluation]] fields + * transition to true is significant. + */ if (moduleRecord.getPendingAsyncDependencies() == 0) { moduleAsyncExecution(realm, moduleRecord); } @@ -944,6 +949,7 @@ private static Object asyncModuleExecutionFulfilled(JSRealm realm, JSModuleRecor assert module.getStatus() == Status.EvaluatingAsync; assert module.isAsyncEvaluation(); assert module.getEvaluationError() == null; + module.setAsyncEvaluation(false); module.setStatus(Status.Evaluated); if (module.getTopLevelCapability() != null) { assert module.getCycleRoot() == module; @@ -964,6 +970,7 @@ public int compare(JSModuleRecord o1, JSModuleRecord o2) { } else { try { moduleExecution(realm, m, null); + m.setAsyncEvaluation(false); m.setStatus(Status.Evaluated); if (m.getTopLevelCapability() != null) { assert m.getCycleRoot() == m; @@ -989,6 +996,13 @@ private static Object asyncModuleExecutionRejected(JSRealm realm, JSModuleRecord assert module.getEvaluationError() == null; module.setEvaluationError(JSRuntime.getException(error)); module.setStatus(Status.Evaluated); + module.setAsyncEvaluation(false); + /* + * NOTE: _module_.[[AsyncEvaluation]] is set to *false* for symmetry with + * AsyncModuleExecutionFulfilled. In InnerModuleEvaluation, the value of a module's + * [[AsyncEvaluation]] internal slot is unused when its [[EvaluationError]] internal slot is + * not ~empty~. + */ for (JSModuleRecord m : module.getAsyncParentModules()) { asyncModuleExecutionRejected(realm, m, error); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java index f736ad1414c..13e0ef4511f 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleRecord.java @@ -265,7 +265,9 @@ public void setUnlinked() { private JSModuleRecord cycleRoot = this; // [[HasTLA]] private final boolean hasTLA; - // [[AsyncEvaluation]] (true when asyncEvaluationOrder > 0) + // [[AsyncEvaluation]] + private boolean asyncEvaluation; + // Order in which [[AsyncEvaluation]] was set (if > 0) private long asyncEvaluationOrder; // [[TopLevelCapability]] private PromiseCapabilityRecord topLevelPromiseCapability = null; @@ -283,7 +285,11 @@ public void setTopLevelCapability(PromiseCapabilityRecord capability) { } public boolean isAsyncEvaluation() { - return asyncEvaluationOrder > 0; + return asyncEvaluation; + } + + public void setAsyncEvaluation(boolean asyncEvaluation) { + this.asyncEvaluation = asyncEvaluation; } public List getAsyncParentModules() { From 190c6b5abc4c7f398a2b1dbb90ddd1f06be05ab1 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 19 Aug 2024 17:32:50 +0200 Subject: [PATCH 208/265] Update test262 status. --- graal-js/test/test262.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/graal-js/test/test262.json b/graal-js/test/test262.json index dd420aae037..b667f0b462a 100644 --- a/graal-js/test/test262.json +++ b/graal-js/test/test262.json @@ -3815,9 +3815,5 @@ "filePath" : "staging/Temporal/ZonedDateTime/old/string-parsing.js", "status" : "FAIL", "comment" : "new failures 2023-11-17" - }, { - "filePath" : "staging/top-level-await/tla-hang-entry.js", - "status" : "FAIL", - "comment" : "new failures 2024-08-09" } ] } From a3ac1929e8c9334b5003f1a5f2059fd59ad8db62 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 26 Aug 2024 16:54:55 +0200 Subject: [PATCH 209/265] Simplify ImportCallNode.execute(). --- .../js/nodes/promise/ImportCallNode.java | 132 ++++++++---------- 1 file changed, 57 insertions(+), 75 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java index a552fad0c4e..44f0b890cff 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java @@ -72,7 +72,6 @@ import com.oracle.truffle.js.runtime.JSException; import com.oracle.truffle.js.runtime.JSFrameUtil; import com.oracle.truffle.js.runtime.JSRealm; -import com.oracle.truffle.js.runtime.JSRuntime; import com.oracle.truffle.js.runtime.JavaScriptRealmBoundaryRootNode; import com.oracle.truffle.js.runtime.JavaScriptRootNode; import com.oracle.truffle.js.runtime.Strings; @@ -140,14 +139,11 @@ public static ImportCallNode create(JSContext context) { public Object execute(VirtualFrame frame) { ScriptOrModule referencingScriptOrModule = activeScriptOrModule; Object specifier = argRefNode.execute(frame); + Object options = Undefined.instance; if (optionsRefNode != null) { - return executeAttributes(frame, referencingScriptOrModule, specifier); - } else { - return executeWithoutAttributes(referencingScriptOrModule, specifier); + options = optionsRefNode.execute(frame); } - } - private Object executeWithoutAttributes(ScriptOrModule referencingScriptOrModule, Object specifier) { PromiseCapabilityRecord promiseCapability = newPromiseCapability(); TruffleString specifierString; try { @@ -155,79 +151,73 @@ private Object executeWithoutAttributes(ScriptOrModule referencingScriptOrModule } catch (AbstractTruffleException ex) { return rejectPromise(promiseCapability, ex); } - return hostImportModuleDynamicallyWithSite(referencingScriptOrModule, ModuleRequest.create(specifierString, phase), promiseCapability); - } - @SuppressWarnings("unchecked") - private Object executeAttributes(VirtualFrame frame, ScriptOrModule referencingScriptOrModule, Object specifier) { - assert optionsRefNode != null; - if (enumerableOwnPropertyNamesNode == null || getWithNode == null || getAssertNode == null) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - enumerableOwnPropertyNamesNode = insert(EnumerableOwnPropertyNamesNode.createKeys(context)); - getWithNode = insert(PropertyGetNode.create(Strings.WITH, context)); - getAssertNode = insert(PropertyGetNode.create(ASSERT, context)); - } - Object options = optionsRefNode.execute(frame); - PromiseCapabilityRecord promiseCapability = newPromiseCapability(); - TruffleString specifierString; - try { - specifierString = toStringNode.executeString(specifier); - } catch (AbstractTruffleException ex) { - return rejectPromise(promiseCapability, ex); - } Map.Entry[] attributes = null; if (options != Undefined.instance) { - if (!JSRuntime.isObject(options)) { - return rejectPromiseWithTypeError(promiseCapability, "The second argument to import() must be an object"); - } - Object attributesObj = Undefined.instance; try { - if (context.getLanguageOptions().importAttributes()) { - attributesObj = getWithNode.getValue(options); - } - if (attributesObj == Undefined.instance) { - if (context.getLanguageOptions().importAssertions()) { - attributesObj = getAssertNode.getValue(options); - } + if (!(options instanceof JSObject optionsObj)) { + throw Errors.createTypeError("The second argument to import() must be an object", this); } + attributes = getAttributes(optionsObj); } catch (AbstractTruffleException ex) { return rejectPromise(promiseCapability, ex); } - if (attributesObj != Undefined.instance) { - if (!(attributesObj instanceof JSObject obj)) { - return rejectPromiseWithTypeError(promiseCapability, "The 'assert' option must be an object"); - } - UnmodifiableArrayList keys; - try { - keys = enumerableOwnPropertyNamesNode.execute(obj); - } catch (AbstractTruffleException ex) { - return rejectPromise(promiseCapability, ex); - } - attributes = (Map.Entry[]) new Map.Entry[keys.size()]; - boolean allStrings = true; - for (int i = 0; i < keys.size(); i++) { - TruffleString key = (TruffleString) keys.get(i); - Object value; - try { - value = JSObject.get(obj, key); - } catch (AbstractTruffleException ex) { - return rejectPromise(promiseCapability, ex); - } - if (value instanceof TruffleString valueStr) { - attributes[i] = Boundaries.mapEntry(key, valueStr); - } else { - // Read all values before rejecting the promise, - // we were supposed to do EnumerableOwnProperties(KEY+VALUE) above. - allStrings = false; - } + } + ModuleRequest moduleRequest = attributes == null ? ModuleRequest.create(specifierString, phase) : createModuleRequestWithAttributes(specifierString, attributes, phase); + return hostImportModuleDynamicallyWithSite(referencingScriptOrModule, moduleRequest, promiseCapability); + } + + @SuppressWarnings("unchecked") + private Map.Entry[] getAttributes(JSObject options) { + Object attributesObj = Undefined.instance; + if (context.getLanguageOptions().importAttributes()) { + if (getWithNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + getWithNode = insert(PropertyGetNode.create(Strings.WITH, context)); + } + attributesObj = getWithNode.getValue(options); + } + if (attributesObj == Undefined.instance) { + if (context.getLanguageOptions().importAssertions()) { + if (getAssertNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + getAssertNode = insert(PropertyGetNode.create(ASSERT, context)); } - if (!allStrings) { - return rejectPromiseWithTypeError(promiseCapability, "Import assertion value must be a string"); + attributesObj = getAssertNode.getValue(options); + } + } + Map.Entry[] attributes = null; + if (attributesObj != Undefined.instance) { + if (!(attributesObj instanceof JSObject obj)) { + throw Errors.createTypeError(context.getLanguageOptions().importAssertions() + ? "The 'assert' option must be an object" + : "The 'with' option must be an object", this); + } + if (enumerableOwnPropertyNamesNode == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + enumerableOwnPropertyNamesNode = insert(EnumerableOwnPropertyNamesNode.createKeys(context)); + } + UnmodifiableArrayList keys = enumerableOwnPropertyNamesNode.execute(obj); + attributes = (Map.Entry[]) new Map.Entry[keys.size()]; + boolean allStrings = true; + for (int i = 0; i < keys.size(); i++) { + TruffleString key = (TruffleString) keys.get(i); + Object value = JSObject.get(obj, key); + if (value instanceof TruffleString valueStr) { + attributes[i] = Boundaries.mapEntry(key, valueStr); + } else { + // Read all values before rejecting the promise, + // we were supposed to do EnumerableOwnProperties(KEY+VALUE) above. + allStrings = false; } } + if (!allStrings) { + throw Errors.createTypeError(context.getLanguageOptions().importAssertions() + ? "Import assertion value must be a string" + : "Import attribute value must be a string", this); + } } - ModuleRequest moduleRequest = attributes == null ? ModuleRequest.create(specifierString, phase) : createModuleRequestWithAttributes(specifierString, attributes, phase); - return hostImportModuleDynamicallyWithSite(referencingScriptOrModule, moduleRequest, promiseCapability); + return attributes; } private JSDynamicObject hostImportModuleDynamicallyWithSite(ScriptOrModule referrer, ModuleRequest moduleRequest, PromiseCapabilityRecord promiseCapability) { @@ -280,14 +270,6 @@ private JSDynamicObject rejectPromise(PromiseCapabilityRecord promiseCapability, return promiseCapability.getPromise(); } - private Object rejectPromiseWithTypeError(PromiseCapabilityRecord promiseCapability, String errorMessage) { - if (callRejectNode == null) { - // Just to cut off before createTypeError. Nodes are initialized in rejectPromise(). - CompilerDirectives.transferToInterpreterAndInvalidate(); - } - return rejectPromise(promiseCapability, Errors.createTypeError(errorMessage, this)); - } - @TruffleBoundary private static JSException createTypeErrorCannotImport(TruffleString specifier) { return Errors.createError("Cannot dynamically import module: " + specifier); From 904b2b4c684445fa66d90f0d7175f188ae549255 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Mon, 19 Aug 2024 15:17:37 +0200 Subject: [PATCH 210/265] Add basic test for source phase wasm module import. --- .../wasm/source-phase-import-dynamic.mjs | 23 ++++++++++++++++++ .../wasm/source-phase-import.mjs | 23 ++++++++++++++++++ .../wasm/source-phase-import.wasm | Bin 0 -> 41 bytes .../wasm/source-phase-import.wat | 13 ++++++++++ 4 files changed, 59 insertions(+) create mode 100644 graal-js/src/com.oracle.truffle.js.test/wasm/source-phase-import-dynamic.mjs create mode 100644 graal-js/src/com.oracle.truffle.js.test/wasm/source-phase-import.mjs create mode 100644 graal-js/src/com.oracle.truffle.js.test/wasm/source-phase-import.wasm create mode 100644 graal-js/src/com.oracle.truffle.js.test/wasm/source-phase-import.wat diff --git a/graal-js/src/com.oracle.truffle.js.test/wasm/source-phase-import-dynamic.mjs b/graal-js/src/com.oracle.truffle.js.test/wasm/source-phase-import-dynamic.mjs new file mode 100644 index 00000000000..0d9f34a5b1a --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/wasm/source-phase-import-dynamic.mjs @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ + +/** + * Test source phase imports. + * + * @option webassembly + * @option source-phase-imports + */ + +const wasmModule = await import.source("./source-phase-import.wasm"); + +load('../js/assert.js'); + +assertTrue(wasmModule instanceof WebAssembly.Module); +assertSame("WebAssembly.Module", wasmModule[Symbol.toStringTag]); + +const instance = new WebAssembly.Instance(wasmModule); +assertSame(481, instance.exports.mul(13, 37)); diff --git a/graal-js/src/com.oracle.truffle.js.test/wasm/source-phase-import.mjs b/graal-js/src/com.oracle.truffle.js.test/wasm/source-phase-import.mjs new file mode 100644 index 00000000000..94cad88ea2a --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/wasm/source-phase-import.mjs @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. + */ + +/** + * Test source phase imports. + * + * @option webassembly + * @option source-phase-imports + */ + +import source wasmModule from "./source-phase-import.wasm"; + +load('../js/assert.js'); + +assertTrue(wasmModule instanceof WebAssembly.Module); +assertSame("WebAssembly.Module", wasmModule[Symbol.toStringTag]); + +const instance = new WebAssembly.Instance(wasmModule); +assertSame(481, instance.exports.mul(13, 37)); diff --git a/graal-js/src/com.oracle.truffle.js.test/wasm/source-phase-import.wasm b/graal-js/src/com.oracle.truffle.js.test/wasm/source-phase-import.wasm new file mode 100644 index 0000000000000000000000000000000000000000..0a878c60116e1702b3c292d795e08ab7d9926e17 GIT binary patch literal 41 vcmV~$u@L|u2n4}<4H&fvO4A%7$C%dL<=hk?({5F&-h`QYzJNJoIIdV9elZ1Q literal 0 HcmV?d00001 diff --git a/graal-js/src/com.oracle.truffle.js.test/wasm/source-phase-import.wat b/graal-js/src/com.oracle.truffle.js.test/wasm/source-phase-import.wat new file mode 100644 index 00000000000..730dc8a4c5b --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/wasm/source-phase-import.wat @@ -0,0 +1,13 @@ +;; +;; Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. +;; Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl. +;; + +(module + (func $mul (param i32 i32) (result i32) + local.get 0 + local.get 1 + i32.mul + ) + (export "mul" (func $mul)) +) From 69c6c87c8c457ef43b551f6398611d693ffd8be5 Mon Sep 17 00:00:00 2001 From: Volker Simonis Date: Thu, 29 Aug 2024 13:08:17 +0200 Subject: [PATCH 211/265] GraalJSScriptEngine: NPE when setting empty engine bindings Fixes #839 --- .../js/scriptengine/test/TestBindings.java | 16 ++++++++++++++++ .../truffle/js/scriptengine/GraalJSBindings.java | 6 +++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/graal-js/src/com.oracle.truffle.js.scriptengine.test/src/com/oracle/truffle/js/scriptengine/test/TestBindings.java b/graal-js/src/com.oracle.truffle.js.scriptengine.test/src/com/oracle/truffle/js/scriptengine/test/TestBindings.java index 65712b291b7..b7909dacac6 100644 --- a/graal-js/src/com.oracle.truffle.js.scriptengine.test/src/com/oracle/truffle/js/scriptengine/test/TestBindings.java +++ b/graal-js/src/com.oracle.truffle.js.scriptengine.test/src/com/oracle/truffle/js/scriptengine/test/TestBindings.java @@ -80,6 +80,22 @@ private ScriptEngine getEngine() { return manager.getEngineByName(TestEngine.TESTED_ENGINE_NAME); } + @Test + public void engineEmptyBindings() { + ScriptEngine engine = getEngine(); + Bindings bindings = engine.createBindings(); + engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE); + assertEquals(bindings, engine.getBindings(ScriptContext.ENGINE_SCOPE)); + } + + @Test + public void globalEmptyBindings() { + ScriptEngine engine = getEngine(); + Bindings bindings = engine.createBindings(); + engine.setBindings(bindings, ScriptContext.GLOBAL_SCOPE); + assertEquals(bindings, engine.getBindings(ScriptContext.GLOBAL_SCOPE)); + } + @Test public void enginePut() throws ScriptException { ScriptEngine engine = getEngine(); diff --git a/graal-js/src/com.oracle.truffle.js.scriptengine/src/com/oracle/truffle/js/scriptengine/GraalJSBindings.java b/graal-js/src/com.oracle.truffle.js.scriptengine/src/com/oracle/truffle/js/scriptengine/GraalJSBindings.java index 4b9588d365e..d64a03df0f8 100644 --- a/graal-js/src/com.oracle.truffle.js.scriptengine/src/com/oracle/truffle/js/scriptengine/GraalJSBindings.java +++ b/graal-js/src/com.oracle.truffle.js.scriptengine/src/com/oracle/truffle/js/scriptengine/GraalJSBindings.java @@ -219,7 +219,11 @@ void importGlobalBindings(ScriptContext scriptContext) { void updateEngineScriptContext(ScriptContext scriptContext) { engineScriptContext = scriptContext; - updateContextBinding(); + if (context != null) { + updateContextBinding(); + } else { + initContext(); // This will also call updateContextBinding() + } } } From 96fdf77a0965e6eb1a672973b6388974bc6f1839 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 29 Aug 2024 16:05:15 +0200 Subject: [PATCH 212/265] Move reportLoopCount to JavaScriptBaseNode. --- .../truffle/js/builtins/ArrayPrototypeBuiltins.java | 7 ------- .../oracle/truffle/js/nodes/JavaScriptBaseNode.java | 12 ++++++++++++ .../js/nodes/access/ForEachIndexCallNode.java | 9 ++++----- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java index ec82c8d1cf6..75f7fc8ee55 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java @@ -69,7 +69,6 @@ import com.oracle.truffle.api.interop.UnsupportedTypeException; import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.DirectCallNode; -import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.SlowPathException; import com.oracle.truffle.api.nodes.UnexpectedResultException; @@ -464,12 +463,6 @@ protected final JSTypedArrayObject validateTypedArray(Object obj) { protected void reportLoopCount(long count) { reportLoopCount(this, count); } - - public static void reportLoopCount(Node node, long count) { - if (count > 0) { - LoopNode.reportLoopCount(node, count > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) count); - } - } } protected static class ArraySpeciesConstructorNode extends JavaScriptBaseNode { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/JavaScriptBaseNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/JavaScriptBaseNode.java index acbbd9eff4a..ab8a273a94c 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/JavaScriptBaseNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/JavaScriptBaseNode.java @@ -45,6 +45,7 @@ import com.oracle.truffle.api.dsl.Idempotent; import com.oracle.truffle.api.dsl.ImportStatic; import com.oracle.truffle.api.dsl.TypeSystemReference; +import com.oracle.truffle.api.nodes.LoopNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.nodes.NodeInfo; import com.oracle.truffle.js.lang.JavaScriptLanguage; @@ -98,4 +99,15 @@ protected final boolean hasOverloadedOperators(Object obj) { return (CompilerDirectives.inInterpreter() || getLanguageOptions().operatorOverloading()) && JSGuards.hasOverloadedOperators(obj); } + public static void reportLoopCount(Node node, int count) { + if (count > 0) { + LoopNode.reportLoopCount(node, count); + } + } + + public static void reportLoopCount(Node node, long count) { + if (count > 0) { + LoopNode.reportLoopCount(node, count > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) count); + } + } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ForEachIndexCallNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ForEachIndexCallNode.java index 1d7d6c991dd..8f37b6c44cd 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ForEachIndexCallNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/ForEachIndexCallNode.java @@ -47,7 +47,6 @@ import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.profiles.LoopConditionProfile; -import com.oracle.truffle.js.builtins.ArrayPrototypeBuiltins.BasicArrayOperation; import com.oracle.truffle.js.nodes.JavaScriptBaseNode; import com.oracle.truffle.js.nodes.array.JSArrayFirstElementIndexNode; import com.oracle.truffle.js.nodes.array.JSArrayLastElementIndexNode; @@ -248,7 +247,7 @@ protected Object executeForEachIndexFast(JSDynamicObject target, Object callback count++; index = checkHasProperty ? nextElementIndex(target, index, length) : (index + 1); } - BasicArrayOperation.reportLoopCount(this, count); + reportLoopCount(this, count); return currentResult; } @@ -268,7 +267,7 @@ protected Object executeForEachIndexSlow(Object target, Object callback, Object } } } - BasicArrayOperation.reportLoopCount(this, length - fromIndex); + reportLoopCount(this, length - fromIndex); return currentResult; } @@ -310,7 +309,7 @@ protected Object executeForEachIndexFast(JSDynamicObject target, Object callback count++; index = checkHasProperty ? previousElementIndex(target, index) : (index - 1); } - BasicArrayOperation.reportLoopCount(this, count); + reportLoopCount(this, count); return currentResult; } @@ -330,7 +329,7 @@ protected Object executeForEachIndexSlow(Object target, Object callback, Object } } } - BasicArrayOperation.reportLoopCount(this, fromIndex); + reportLoopCount(this, fromIndex); return currentResult; } From a1e4479cb6dfd103063ebe5414f0d48d3377ec24 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 29 Aug 2024 15:40:47 +0200 Subject: [PATCH 213/265] Report loop count in typed array constructor. --- .../oracle/truffle/js/builtins/JSConstructTypedArrayNode.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/JSConstructTypedArrayNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/JSConstructTypedArrayNode.java index 8bb0c40516b..a0995ea69f3 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/JSConstructTypedArrayNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/JSConstructTypedArrayNode.java @@ -389,6 +389,7 @@ protected JSDynamicObject doObject(JSDynamicObject newTarget, JSObject object, @ Object kValue = values.get(k); writeOwnNode.executeWithTargetAndIndexAndValue(obj, k, kValue); } + reportLoopCount(this, len); return obj; } @@ -402,6 +403,7 @@ protected JSDynamicObject doObject(JSDynamicObject newTarget, JSObject object, @ Object kValue = readNode.executeWithTargetAndIndex(object, k); writeOwnNode.executeWithTargetAndIndexAndValue(obj, k, kValue); } + reportLoopCount(this, len); return obj; } @@ -441,6 +443,7 @@ protected JSDynamicObject doForeignObject(JSDynamicObject newTarget, Object obje Object kValue = JSInteropUtil.readArrayElementOrDefault(object, k, 0, interop, importValue); writeOwnNode.executeWithTargetAndIndexAndValue(obj, k, kValue); } + reportLoopCount(this, length); } return obj; } From 16d63fa0c2cd97781fa832c386eb9be7d66e46a9 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Mon, 2 Sep 2024 10:54:49 +0200 Subject: [PATCH 214/265] Correction of the year in the copyright header. --- .../com/oracle/truffle/js/scriptengine/test/TestBindings.java | 2 +- .../src/com/oracle/truffle/js/scriptengine/GraalJSBindings.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js.scriptengine.test/src/com/oracle/truffle/js/scriptengine/test/TestBindings.java b/graal-js/src/com.oracle.truffle.js.scriptengine.test/src/com/oracle/truffle/js/scriptengine/test/TestBindings.java index b7909dacac6..7178751ec6b 100644 --- a/graal-js/src/com.oracle.truffle.js.scriptengine.test/src/com/oracle/truffle/js/scriptengine/test/TestBindings.java +++ b/graal-js/src/com.oracle.truffle.js.scriptengine.test/src/com/oracle/truffle/js/scriptengine/test/TestBindings.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 diff --git a/graal-js/src/com.oracle.truffle.js.scriptengine/src/com/oracle/truffle/js/scriptengine/GraalJSBindings.java b/graal-js/src/com.oracle.truffle.js.scriptengine/src/com/oracle/truffle/js/scriptengine/GraalJSBindings.java index d64a03df0f8..1a78bb27360 100644 --- a/graal-js/src/com.oracle.truffle.js.scriptengine/src/com/oracle/truffle/js/scriptengine/GraalJSBindings.java +++ b/graal-js/src/com.oracle.truffle.js.scriptengine/src/com/oracle/truffle/js/scriptengine/GraalJSBindings.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 From 8866f8c10dc70311260994fb8f840be3abbe3bd8 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 29 Aug 2024 16:05:45 +0200 Subject: [PATCH 215/265] Report loop count in typed array prototype methods. --- .../truffle/js/builtins/TypedArrayPrototypeBuiltins.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java index 89c9dbed8e2..cac2c2a11a3 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/TypedArrayPrototypeBuiltins.java @@ -458,7 +458,7 @@ private void setFastArray(JSTypedArrayObject thisObj, JSArrayObject array, int o rangeCheck(0, sourceLen, offset, targetArray.length(thisObj)); boolean isBigInt = JSArrayBufferView.isBigIntArrayBufferView(thisObj); - for (int i = 0, j = offset; i < sourceLen; i++, j++) { + for (long i = 0, j = offset; i < sourceLen; i++, j++) { sourceArray = sourceArrayProf.profile(array.getArrayType()); Object value = sourceArray.getElement(array, i); // IntegerIndexedElementSet @@ -468,6 +468,7 @@ private void setFastArray(JSTypedArrayObject thisObj, JSArrayObject array, int o } TruffleSafepoint.poll(this); } + reportLoopCount(this, sourceLen); } private void setOther(JSTypedArrayObject thisObj, Object array, int offset) { @@ -498,6 +499,7 @@ private void setOther(JSTypedArrayObject thisObj, Object array, int offset) { } TruffleSafepoint.poll(this); } + reportLoopCount(this, srcLength); } protected Object toNumber(Object value) { @@ -632,6 +634,7 @@ private void copyTypedArrayElementsDistinctBuffers(JSArrayBufferObject targetBuf } TruffleSafepoint.poll(this); } + reportLoopCount(this, sourceLength); return; } @@ -667,6 +670,7 @@ private void copyTypedArrayElementsDistinctBuffers(JSArrayBufferObject targetBuf TruffleSafepoint.poll(this); } } + reportLoopCount(this, sourceLength); } private ByteBuffer getByteBufferFromInteropBuffer(JSArrayBufferObject interopBuffer) { @@ -709,6 +713,7 @@ private JSArrayBufferObject cloneInteropArrayBuffer(JSArrayBufferObject sourceBu ((TypedArray.TypedIntArray) clonedType).setIntImpl(clonedArrayBuffer, 0, i, value, interop); TruffleSafepoint.poll(this); } + reportLoopCount(this, srcByteLength); return clonedArrayBuffer; } @@ -834,6 +839,7 @@ protected JSDynamicObject reverse(JSTypedArrayObject thisObj, } TruffleSafepoint.poll(this); } + reportLoopCount(this, middle); return thisObj; } @@ -868,6 +874,7 @@ protected JSDynamicObject fill(Object thisObj, Object value, Object start, Objec write(thisJSObj, idx, convValue); TruffleSafepoint.poll(this); } + reportLoopCount(this, lEnd - lStart); return thisJSObj; } } From e8cc90488f97bde80103118fd883e8ad4ed633f6 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Thu, 29 Aug 2024 16:18:05 +0200 Subject: [PATCH 216/265] Insert missing loop counts and safepoints in Array.prototype methods. --- .../js/builtins/ArrayPrototypeBuiltins.java | 25 +++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java index 75f7fc8ee55..eb0b8a0fd48 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ArrayPrototypeBuiltins.java @@ -1511,6 +1511,7 @@ private long concatSpreadable(Object retObj, long n, Object elObj, long len2, fi writeOwn(retObj, n + k, read(elObj, k)); } } + reportLoopCount(len2); return n + len2; } @@ -1779,7 +1780,9 @@ private TruffleString joinLoop(Object thisJSObject, final long length, final Tru } else { i = nextElementIndex(thisJSObject, i, length); } + TruffleSafepoint.poll(this); } + reportLoopCount(length); return builderToString(sb); } @@ -1827,32 +1830,37 @@ private TruffleString joinSparse(Object thisObject, long length, TruffleString j } } i = nextElementIndex(thisObject, i, length); + TruffleSafepoint.poll(this); } if (appendSep) { calculatedLength += (length - 1) * Strings.length(joinSeparator); } if (calculatedLength > getContext().getStringLengthLimit()) { - CompilerDirectives.transferToInterpreter(); + errorBranch.enter(); throw Errors.createRangeErrorInvalidStringLength(); } assert calculatedLength <= Integer.MAX_VALUE; var sb = stringBuilderProfile.newStringBuilder((int) calculatedLength); + int convertedSize = converted.size(); long lastIndex = 0; - for (int j = 0; j < converted.size(); j += 2) { + for (int j = 0; j < convertedSize; j += 2) { long index = (long) converted.get(j); - Object value = converted.get(j + 1); + TruffleString value = (TruffleString) converted.get(j + 1); if (appendSep) { for (long k = lastIndex; k < index; k++) { append(sb, joinSeparator); } } - append(sb, (TruffleString) value); + append(sb, value); lastIndex = index; } if (appendSep) { for (long k = lastIndex; k < length - 1; k++) { append(sb, joinSeparator); } + reportLoopCount(length); + } else { + reportLoopCount(convertedSize / 2); } assert StringBuilderProfile.length(sb) == calculatedLength; return builderToString(sb); @@ -1899,9 +1907,8 @@ protected TruffleString toLocaleString(VirtualFrame frame, Object thisObj, } else { userArguments = JSArguments.EMPTY_ARGUMENTS_ARRAY; } - long k = 0; var sb = stringBuilderProfile.newStringBuilder(); - while (k < len) { + for (long k = 0; k < len; k++) { if (k > 0) { stringBuilderProfile.append(appendCharNode, sb, ','); } @@ -1911,8 +1918,9 @@ protected TruffleString toLocaleString(VirtualFrame frame, Object thisObj, TruffleString resultString = toStringNode.executeString(result); stringBuilderProfile.append(appendStringNode, sb, resultString); } - k++; + TruffleSafepoint.poll(this); } + reportLoopCount(len); return StringBuilderProfile.toString(builderToStringNode, sb); } finally { realm.joinStackPop(); @@ -2718,6 +2726,7 @@ protected Object reverse(final Object thisObj) { var value = read(thisJSObj, length - 1 - i); write(result, i, value); } + reportLoopCount(length); return result; } } @@ -2764,6 +2773,7 @@ protected final JSArrayObject toSorted(Object thisObj, Object compare, for (int i = 0; i < length; i++) { write(result, i, array[i]); } + reportLoopCount(length); return result; } } @@ -2897,6 +2907,7 @@ private Object[] foreignArrayToObjectArray(Object thisObj, int len) { Object[] array = new Object[len]; for (int index = 0; index < len; index++) { array[index] = JSInteropUtil.readArrayElementOrDefault(thisObj, index, Undefined.instance, interop, importValue); + TruffleSafepoint.poll(this); } return array; } From 3ae05aa70723b04d75e4083db1cc49bde2a8da3c Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Tue, 3 Sep 2024 17:01:29 +0200 Subject: [PATCH 217/265] Allow non-Int Contiguous*Array to ZeroBased*Array conversions in WriteElementNode. --- .../js/nodes/access/WriteElementNode.java | 66 +++++++++++++------ 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/WriteElementNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/WriteElementNode.java index fbfe3728a96..b731a7a64b9 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/WriteElementNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/access/WriteElementNode.java @@ -135,7 +135,10 @@ import com.oracle.truffle.js.runtime.array.dyn.AbstractObjectArray; import com.oracle.truffle.js.runtime.array.dyn.AbstractWritableArray; import com.oracle.truffle.js.runtime.array.dyn.AbstractWritableArray.SetSupportedProfileAccess; +import com.oracle.truffle.js.runtime.array.dyn.ContiguousDoubleArray; import com.oracle.truffle.js.runtime.array.dyn.ContiguousIntArray; +import com.oracle.truffle.js.runtime.array.dyn.ContiguousJSObjectArray; +import com.oracle.truffle.js.runtime.array.dyn.ContiguousObjectArray; import com.oracle.truffle.js.runtime.array.dyn.HolesDoubleArray; import com.oracle.truffle.js.runtime.array.dyn.HolesIntArray; import com.oracle.truffle.js.runtime.array.dyn.HolesJSObjectArray; @@ -959,7 +962,8 @@ protected boolean doDoubleArray(JSDynamicObject target, AbstractDoubleArray doub @Cached InlinedBranchProfile objectValueBranch, @Cached InlinedConditionProfile inBoundsFastIf, @Cached InlinedConditionProfile inBoundsIf, - @Cached InlinedConditionProfile supportedIf, + @Cached InlinedConditionProfile supportedNonZeroIf, + @Cached InlinedConditionProfile supportedZeroIf, @Cached InlinedConditionProfile supportedContiguousIf, @Cached InlinedConditionProfile supportedHolesIf, @Cached InlinedBranchProfile needPrototypeBranch, @@ -978,7 +982,8 @@ protected boolean doDoubleArray(JSDynamicObject target, AbstractDoubleArray doub return executeWithDoubleValueInner(target, doubleArray, index, doubleValue, root, inBoundsFastIf, inBoundsIf, - supportedIf, + supportedNonZeroIf, + supportedZeroIf, supportedContiguousIf, supportedHolesIf, needPrototypeBranch, @@ -988,7 +993,8 @@ protected boolean doDoubleArray(JSDynamicObject target, AbstractDoubleArray doub private boolean executeWithDoubleValueInner(JSDynamicObject target, AbstractDoubleArray doubleArray, long index, double doubleValue, WriteElementNode root, @Cached InlinedConditionProfile inBoundsFastIf, @Cached InlinedConditionProfile inBoundsIf, - @Cached InlinedConditionProfile supportedIf, + @Cached InlinedConditionProfile supportedNonZeroIf, + @Cached InlinedConditionProfile supportedZeroIf, @Cached InlinedConditionProfile supportedContiguousIf, @Cached InlinedConditionProfile supportedHolesIf, @Cached InlinedBranchProfile needPrototypeBranch, @@ -999,18 +1005,20 @@ private boolean executeWithDoubleValueInner(JSDynamicObject target, AbstractDoub return false; } int iIndex = (int) index; - if (inBoundsFastIf.profile(this, doubleArray.isInBoundsFast(target, index))) { + if (inBoundsFastIf.profile(this, doubleArray.isInBoundsFast(target, index) && !mightTransferToNonContiguous(doubleArray, target, index))) { doubleArray.setInBoundsFast(target, iIndex, doubleValue); return true; - } else if (inBoundsIf.profile(this, doubleArray.isInBounds(target, iIndex))) { + } else if (inBoundsIf.profile(this, doubleArray.isInBounds(target, iIndex) && !mightTransferToNonContiguous(doubleArray, target, index))) { doubleArray.setInBounds(target, iIndex, doubleValue, this, setSupportedProfile); return true; - } else if (supportedIf.profile(this, doubleArray.isSupported(target, index))) { + } else if (supportedNonZeroIf.profile(this, doubleArray.isSupported(target, index) && !mightTransferToNonContiguous(doubleArray, target, index))) { doubleArray.setSupported(target, iIndex, doubleValue, this, setSupportedProfile); return true; } else { ScriptArray toArrayType; - if (supportedContiguousIf.profile(this, !(doubleArray instanceof AbstractContiguousDoubleArray) && doubleArray.isSupportedContiguous(target, index))) { + if (supportedZeroIf.profile(this, mightTransferToNonContiguous(doubleArray, target, index) && doubleArray.isSupported(target, index))) { + toArrayType = doubleArray.toNonContiguous(target, iIndex, doubleValue, this, setSupportedProfile); + } else if (supportedContiguousIf.profile(this, !(doubleArray instanceof AbstractContiguousDoubleArray) && doubleArray.isSupportedContiguous(target, index))) { toArrayType = doubleArray.toContiguous(target, index, doubleValue); } else if (supportedHolesIf.profile(this, doubleArray.isSupportedHoles(target, index))) { toArrayType = doubleArray.toHoles(target, index, doubleValue); @@ -1021,6 +1029,10 @@ private boolean executeWithDoubleValueInner(JSDynamicObject target, AbstractDoub return setArrayAndWrite(toArrayType, target, index, doubleValue, root); } } + + private static boolean mightTransferToNonContiguous(AbstractDoubleArray doubleArray, JSDynamicObject target, long index) { + return doubleArray instanceof ContiguousDoubleArray && index == 0 && doubleArray.firstElementIndex(target) == 1 && JSAbstractArray.arrayGetIndexOffset(target) == 0; + } } abstract static class ObjectArrayWriteElementCacheNode extends RecursiveCachedArrayWriteElementCacheNode { @@ -1033,7 +1045,8 @@ abstract static class ObjectArrayWriteElementCacheNode extends RecursiveCachedAr protected boolean doObjectArray(JSDynamicObject target, AbstractObjectArray objectArray, long index, Object value, WriteElementNode root, @Cached InlinedConditionProfile inBoundsFastIf, @Cached InlinedConditionProfile inBoundsIf, - @Cached InlinedConditionProfile supportedIf, + @Cached InlinedConditionProfile supportedNonZeroIf, + @Cached InlinedConditionProfile supportedZeroIf, @Cached InlinedConditionProfile supportedContiguousIf, @Cached InlinedConditionProfile supportedHolesIf, @Cached InlinedBranchProfile needPrototypeBranch, @@ -1044,18 +1057,20 @@ protected boolean doObjectArray(JSDynamicObject target, AbstractObjectArray obje return false; } int iIndex = (int) index; - if (inBoundsFastIf.profile(this, objectArray.isInBoundsFast(target, index))) { + if (inBoundsFastIf.profile(this, objectArray.isInBoundsFast(target, index) && !mightTransferToNonContiguous(objectArray, target, index))) { objectArray.setInBoundsFast(target, iIndex, value); return true; - } else if (inBoundsIf.profile(this, objectArray.isInBounds(target, iIndex))) { + } else if (inBoundsIf.profile(this, objectArray.isInBounds(target, iIndex) && !mightTransferToNonContiguous(objectArray, target, index))) { objectArray.setInBounds(target, iIndex, value, this, setSupportedProfile); return true; - } else if (supportedIf.profile(this, objectArray.isSupported(target, index))) { + } else if (supportedNonZeroIf.profile(this, objectArray.isSupported(target, index) && !mightTransferToNonContiguous(objectArray, target, index))) { objectArray.setSupported(target, iIndex, value, this, setSupportedProfile); return true; } else { ScriptArray toArrayType; - if (supportedContiguousIf.profile(this, !(objectArray instanceof AbstractContiguousObjectArray) && objectArray.isSupportedContiguous(target, index))) { + if (supportedZeroIf.profile(this, mightTransferToNonContiguous(objectArray, target, index) && objectArray.isSupported(target, index))) { + toArrayType = objectArray.toNonContiguous(target, iIndex, value, this, setSupportedProfile); + } else if (supportedContiguousIf.profile(this, !(objectArray instanceof AbstractContiguousObjectArray) && objectArray.isSupportedContiguous(target, index))) { toArrayType = objectArray.toContiguous(target, index, value); } else if (supportedHolesIf.profile(this, objectArray.isSupportedHoles(target, index))) { toArrayType = objectArray.toHoles(target, index, value); @@ -1066,6 +1081,10 @@ protected boolean doObjectArray(JSDynamicObject target, AbstractObjectArray obje return setArrayAndWrite(toArrayType, target, index, value, root); } } + + private static boolean mightTransferToNonContiguous(AbstractObjectArray objectArray, JSDynamicObject target, long index) { + return objectArray instanceof ContiguousObjectArray && index == 0 && objectArray.firstElementIndex(target) == 1 && JSAbstractArray.arrayGetIndexOffset(target) == 0; + } } abstract static class JSObjectArrayWriteElementCacheNode extends RecursiveCachedArrayWriteElementCacheNode { @@ -1080,7 +1099,8 @@ protected boolean doJSObjectArray(JSDynamicObject target, AbstractJSObjectArray @Cached InlinedBranchProfile objectValueBranch, @Cached InlinedConditionProfile inBoundsFastIf, @Cached InlinedConditionProfile inBoundsIf, - @Cached InlinedConditionProfile supportedIf, + @Cached InlinedConditionProfile supportedNonZeroIf, + @Cached InlinedConditionProfile supportedZeroIf, @Cached InlinedConditionProfile supportedContiguousIf, @Cached InlinedConditionProfile supportedHolesIf, @Cached InlinedBranchProfile needPrototypeBranch, @@ -1091,7 +1111,8 @@ protected boolean doJSObjectArray(JSDynamicObject target, AbstractJSObjectArray return executeWithJSObjectValueInner(target, jsobjectArray, index, jsobjectValue, root, inBoundsFastIf, inBoundsIf, - supportedIf, + supportedNonZeroIf, + supportedZeroIf, supportedContiguousIf, supportedHolesIf, needPrototypeBranch, @@ -1105,7 +1126,8 @@ protected boolean doJSObjectArray(JSDynamicObject target, AbstractJSObjectArray private boolean executeWithJSObjectValueInner(JSDynamicObject target, AbstractJSObjectArray jsobjectArray, long index, JSDynamicObject jsobjectValue, WriteElementNode root, InlinedConditionProfile inBoundsFastIf, InlinedConditionProfile inBoundsIf, - InlinedConditionProfile supportedIf, + @Cached InlinedConditionProfile supportedNonZeroIf, + @Cached InlinedConditionProfile supportedZeroIf, InlinedConditionProfile supportedContiguousIf, InlinedConditionProfile supportedHolesIf, InlinedBranchProfile needPrototypeBranch, @@ -1116,18 +1138,20 @@ private boolean executeWithJSObjectValueInner(JSDynamicObject target, AbstractJS needPrototypeBranch.enter(this); return false; } - if (inBoundsFastIf.profile(this, jsobjectArray.isInBoundsFast(target, index))) { + if (inBoundsFastIf.profile(this, jsobjectArray.isInBoundsFast(target, index) && !mightTransferToNonContiguous(jsobjectArray, target, index))) { jsobjectArray.setInBoundsFast(target, iIndex, jsobjectValue); return true; - } else if (inBoundsIf.profile(this, jsobjectArray.isInBounds(target, iIndex))) { + } else if (inBoundsIf.profile(this, jsobjectArray.isInBounds(target, iIndex) && !mightTransferToNonContiguous(jsobjectArray, target, index))) { jsobjectArray.setInBounds(target, iIndex, jsobjectValue, this, setSupportedProfile); return true; - } else if (supportedIf.profile(this, jsobjectArray.isSupported(target, index))) { + } else if (supportedNonZeroIf.profile(this, jsobjectArray.isSupported(target, index) && !mightTransferToNonContiguous(jsobjectArray, target, index))) { jsobjectArray.setSupported(target, iIndex, jsobjectValue, this, setSupportedProfile); return true; } else { ScriptArray toArrayType; - if (supportedContiguousIf.profile(this, !(jsobjectArray instanceof AbstractContiguousJSObjectArray) && jsobjectArray.isSupportedContiguous(target, index))) { + if (supportedZeroIf.profile(this, mightTransferToNonContiguous(jsobjectArray, target, index) && jsobjectArray.isSupported(target, index))) { + toArrayType = jsobjectArray.toNonContiguous(target, iIndex, jsobjectValue, this, setSupportedProfile); + } else if (supportedContiguousIf.profile(this, !(jsobjectArray instanceof AbstractContiguousJSObjectArray) && jsobjectArray.isSupportedContiguous(target, index))) { toArrayType = jsobjectArray.toContiguous(target, index, jsobjectValue); } else if (supportedHolesIf.profile(this, jsobjectArray.isSupportedHoles(target, index))) { toArrayType = jsobjectArray.toHoles(target, index, jsobjectValue); @@ -1138,6 +1162,10 @@ private boolean executeWithJSObjectValueInner(JSDynamicObject target, AbstractJS return setArrayAndWrite(toArrayType, target, index, jsobjectValue, root); } } + + private static boolean mightTransferToNonContiguous(AbstractJSObjectArray jsobjectArray, JSDynamicObject target, long index) { + return jsobjectArray instanceof ContiguousJSObjectArray && index == 0 && jsobjectArray.firstElementIndex(target) == 1 && JSAbstractArray.arrayGetIndexOffset(target) == 0; + } } abstract static class HolesIntArrayWriteElementCacheNode extends RecursiveCachedArrayWriteElementCacheNode { From 3c0a4aabc0b6a97776abc980057a9a88a4734dd5 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Tue, 3 Sep 2024 20:57:10 +0000 Subject: [PATCH 218/265] Update graal import. --- graal-js/mx.graal-js/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/mx.graal-js/suite.py b/graal-js/mx.graal-js/suite.py index 22e2fd84f52..1e881a5afb8 100644 --- a/graal-js/mx.graal-js/suite.py +++ b/graal-js/mx.graal-js/suite.py @@ -24,7 +24,7 @@ { "name" : "regex", "subdir" : True, - "version" : "7227e7620849054055835c6719acba43d48e36c4", + "version" : "f4676a7a75e64e7ef2333f2f3f070a58b93eefe2", "urls" : [ {"url" : "https://github.com/oracle/graal.git", "kind" : "git"}, ] From df5bdde0d34d078ad41a11ee19226bbb2e908af2 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Tue, 3 Sep 2024 20:57:11 +0000 Subject: [PATCH 219/265] Sync CI files. --- common.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/common.json b/common.json index 1e47cd9bdfd..467c4edfdcc 100644 --- a/common.json +++ b/common.json @@ -4,11 +4,11 @@ "Jsonnet files should not include this file directly but use ci/common.jsonnet instead." ], - "mx_version": "7.28.0", + "mx_version": "7.29.5", "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { - "galahad-jdk": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+9-885", "platformspecific": true, "extrabundles": ["static-libs"]}, + "galahad-jdk": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+12-1236", "platformspecific": true, "extrabundles": ["static-libs"]}, "oraclejdk11": {"name": "jpg-jdk", "version": "11.0.11", "build_id": "jdk-11.0.11+9", "platformspecific": true, "extrabundles": ["static-libs"] }, @@ -45,13 +45,13 @@ "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.2+13-jvmci-23.1-b33-sulong", "platformspecific": true }, "graalvm-ee-21": {"name": "graalvm-java21", "version": "23.1.3", "platformspecific": true }, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+11", "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+11-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+11-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+11-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+11-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+11-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+11-jvmci-b01-sulong", "platformspecific": true } + "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+12", "platformspecific": true, "extrabundles": ["static-libs"]}, + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+12-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+12-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+12-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+12-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+12-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+12-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { From 8f17b3c9d1cc8b9c0c67bf982e9152a3726c72ed Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Tue, 3 Sep 2024 19:41:45 +0200 Subject: [PATCH 220/265] Call Source.findMimeType on canonical file path. --- .../js/runtime/objects/DefaultESModuleLoader.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java index 331f57aafca..ab8f8cc8b4c 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java @@ -196,8 +196,8 @@ private boolean bareSpecifierDirectLookup(String specifier) { return !(specifier.startsWith(SLASH) || specifier.startsWith(DOT_SLASH) || specifier.startsWith(DOT_DOT_SLASH)); } - protected AbstractModuleRecord loadModuleFromUrl(ScriptOrModule referrer, ModuleRequest moduleRequest, TruffleFile maybeModuleFile, String maybeCanonicalPath) throws IOException { - TruffleFile moduleFile = maybeModuleFile; + protected AbstractModuleRecord loadModuleFromUrl(ScriptOrModule referrer, ModuleRequest moduleRequest, TruffleFile moduleFile, String maybeCanonicalPath) throws IOException { + TruffleFile canonicalFile; String canonicalPath; TruffleLanguage.Env env = realm.getEnv(); if (maybeCanonicalPath == null) { @@ -205,8 +205,10 @@ protected AbstractModuleRecord loadModuleFromUrl(ScriptOrModule referrer, Module * We can only canonicalize the path if I/O is allowed and the file exists; otherwise, * the lookup may still succeed if the module was loaded already (as literal source). */ - canonicalPath = getCanonicalFileIfExists(moduleFile, env).getPath(); + canonicalFile = getCanonicalFileIfExists(moduleFile, env); + canonicalPath = canonicalFile.getPath(); } else { + canonicalFile = moduleFile; canonicalPath = maybeCanonicalPath; } @@ -215,10 +217,10 @@ protected AbstractModuleRecord loadModuleFromUrl(ScriptOrModule referrer, Module return existingModule; } - String mimeType = findMimeType(moduleFile); + String mimeType = findMimeType(canonicalFile); String language = findLanguage(mimeType); - Source source = Source.newBuilder(language, moduleFile).name(Strings.toJavaString(moduleRequest.specifier())).mimeType(mimeType).build(); + Source source = Source.newBuilder(language, canonicalFile).name(Strings.toJavaString(moduleRequest.specifier())).mimeType(mimeType).build(); Map attributes = moduleRequest.attributes(); TruffleString assertedType = attributes.get(JSContext.getTypeImportAttribute()); if (!doesModuleTypeMatchAssertionType(assertedType, mimeType)) { From 3134adc9a7157a99d2c8f0bd14add6dc51a67c7e Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 4 Sep 2024 16:16:58 +0200 Subject: [PATCH 221/265] Update changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c499011d88..76cb7044aed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ See [release calendar](https://www.graalvm.org/release-calendar/) for release da ## Version 24.2.0 * Updated Node.js to version 20.15.1. * Implemented the [`Promise.try`](https://github.com/tc39/proposal-promise-try) proposal. It is available in ECMAScript staging mode (`--js.ecmascript-version=staging`). +* Implemented the [Source Phase Imports](https://github.com/tc39/proposal-source-phase-imports) proposal. It is available behind the experimental option (`--js.source-phase-imports`). * Added option `js.stack-trace-api` that enables/disables `Error.captureStackTrace`, `Error.prepareStackTrace` and `Error.stackTraceLimit`. These non-standard extensions are disabled by default (unless `js.v8-compat` or `js.nashorn-compat` is used). ## Version 24.1.0 From 9d402621753ddedd48bcd73596008e17732f855a Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Thu, 5 Sep 2024 12:48:35 +0200 Subject: [PATCH 222/265] Implementation of Handling Time Zone Canonicalization Changes proposal. --- .../js/builtins/ConstructorBuiltins.java | 6 ++- .../TemporalTimeZonePrototypeBuiltins.java | 27 ++++++++++++++ .../ToRelativeTemporalObjectNode.java | 6 +-- .../ToTemporalTimeZoneSlotValueNode.java | 7 ++-- .../temporal/ToTemporalZonedDateTimeNode.java | 6 +-- .../builtins/intl/JSDateTimeFormat.java | 30 +++++++-------- .../truffle/js/runtime/util/TemporalUtil.java | 37 ++++++++++++++----- 7 files changed, 79 insertions(+), 40 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java index 73bd32dd175..3c46d04d97a 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java @@ -289,6 +289,7 @@ import com.oracle.truffle.js.runtime.objects.ScriptOrModule; import com.oracle.truffle.js.runtime.objects.Undefined; import com.oracle.truffle.js.runtime.util.LRUCache; +import com.oracle.truffle.js.runtime.util.Pair; import com.oracle.truffle.js.runtime.util.SimpleArrayList; import com.oracle.truffle.js.runtime.util.TRegexUtil; import com.oracle.truffle.js.runtime.util.TemporalErrors; @@ -1446,10 +1447,11 @@ private JSDynamicObject constructTemporalTimeZoneIntl(JSDynamicObject newTarget, TruffleString id = idParam; boolean canParse = TemporalUtil.canParseAsTimeZoneNumericUTCOffset(id); if (!canParse) { - id = TemporalUtil.canonicalizeTimeZoneName(id); - if (id == null) { + Pair timeZoneIdentifierRecord = TemporalUtil.getAvailableNamedTimeZoneIdentifier(id); + if (timeZoneIdentifierRecord == null) { throw TemporalErrors.createRangeErrorInvalidTimeZoneString(); } + id = timeZoneIdentifierRecord.getFirst(); } JSRealm realm = getRealm(); JSDynamicObject proto = getPrototype(realm, newTarget); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalTimeZonePrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalTimeZonePrototypeBuiltins.java index 501ea24f680..aa581f5af5c 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalTimeZonePrototypeBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/temporal/TemporalTimeZonePrototypeBuiltins.java @@ -53,6 +53,7 @@ import com.oracle.truffle.api.profiles.InlinedConditionProfile; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.builtins.JSBuiltinsContainer; +import com.oracle.truffle.js.builtins.temporal.TemporalTimeZonePrototypeBuiltinsFactory.JSTemporalTimeZoneEqualsNodeGen; import com.oracle.truffle.js.builtins.temporal.TemporalTimeZonePrototypeBuiltinsFactory.JSTemporalTimeZoneGetInstantForNodeGen; import com.oracle.truffle.js.builtins.temporal.TemporalTimeZonePrototypeBuiltinsFactory.JSTemporalTimeZoneGetNextOrPreviousTransitionNodeGen; import com.oracle.truffle.js.builtins.temporal.TemporalTimeZonePrototypeBuiltinsFactory.JSTemporalTimeZoneGetOffsetNanosecondsForNodeGen; @@ -68,6 +69,8 @@ import com.oracle.truffle.js.nodes.temporal.ToTemporalCalendarSlotValueNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalDateTimeNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalInstantNode; +import com.oracle.truffle.js.nodes.temporal.ToTemporalTimeZoneIdentifierNode; +import com.oracle.truffle.js.nodes.temporal.ToTemporalTimeZoneSlotValueNode; import com.oracle.truffle.js.runtime.BigInt; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRealm; @@ -98,6 +101,7 @@ public enum TemporalTimeZonePrototype implements BuiltinEnum timeZoneIdentifierRecord = TemporalUtil.getAvailableNamedTimeZoneIdentifier(name); + if (timeZoneIdentifierRecord == null) { errorBranch.enter(this); throw TemporalErrors.createRangeErrorInvalidTimeZoneString(); } - return timeZoneName; + return timeZoneIdentifierRecord.getFirst(); } else { errorBranch.enter(this); throw Errors.createTypeErrorNotAString(temporalTimeZoneLike); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalZonedDateTimeNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalZonedDateTimeNode.java index 80674716273..c94249d3353 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalZonedDateTimeNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/temporal/ToTemporalZonedDateTimeNode.java @@ -143,11 +143,7 @@ public JSTemporalZonedDateTimeObject toTemporalZonedDateTime(Object item, JSDyna TruffleString timeZoneName = resultZDT.getTimeZoneResult().getName(); assert timeZoneName != null; if (!TemporalUtil.canParseAsTimeZoneNumericUTCOffset(timeZoneName)) { - timeZoneName = TemporalUtil.canonicalizeTimeZoneName(timeZoneName); - if (timeZoneName == null) { - errorBranch.enter(this); - throw TemporalErrors.createRangeErrorInvalidTimeZoneString(); - } + timeZoneName = (TruffleString) toTimeZoneSlotValue.execute(timeZoneName); } offsetString = resultZDT.getTimeZoneResult().getOffsetString(); if (resultZDT.getTimeZoneResult().isZ()) { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/intl/JSDateTimeFormat.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/intl/JSDateTimeFormat.java index 861e1205685..3627aaa25af 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/intl/JSDateTimeFormat.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/intl/JSDateTimeFormat.java @@ -91,6 +91,7 @@ import com.oracle.truffle.js.runtime.objects.Undefined; import com.oracle.truffle.js.runtime.util.IntlUtil; import com.oracle.truffle.js.runtime.util.LazyValue; +import com.oracle.truffle.js.runtime.util.Pair; public final class JSDateTimeFormat extends JSNonProxy implements JSConstructorFactory.Default.WithFunctions, PrototypeSupplier { @@ -104,7 +105,7 @@ public final class JSDateTimeFormat extends JSNonProxy implements JSConstructorF * Maps the upper-case version of a supported time zone to the corresponding case-regularized * canonical ID. */ - private static final LazyValue> canonicalTimeZoneIDMap = new LazyValue<>(JSDateTimeFormat::initCanonicalTimeZoneIDMap); + private static final LazyValue>> canonicalTimeZoneIDMap = new LazyValue<>(JSDateTimeFormat::initCanonicalTimeZoneIDMap); private JSDateTimeFormat() { } @@ -641,11 +642,15 @@ private static String makeSkeleton(String weekdayOpt, String eraOpt, String year timeZoneNameOptToSkeleton(timeZoneNameOpt); } - private static UnmodifiableEconomicMap initCanonicalTimeZoneIDMap() { + private static UnmodifiableEconomicMap> initCanonicalTimeZoneIDMap() { CompilerAsserts.neverPartOfCompilation(); - EconomicMap map = EconomicMap.create(); + EconomicMap> map = EconomicMap.create(); for (String available : TimeZone.getAvailableIDs()) { - map.put(IntlUtil.toUpperCase(available), TimeZone.getCanonicalID(available)); + String canonical = TimeZone.getCanonicalID(available); + if ("Etc/UTC".equals(canonical) || "Etc/GMT".equals(canonical)) { + canonical = "UTC"; + } + map.put(IntlUtil.toUpperCase(available), new Pair<>(available, canonical)); } return map; } @@ -658,21 +663,14 @@ private static UnmodifiableEconomicMap initCanonicalTimeZoneIDMa */ @TruffleBoundary public static String canonicalizeTimeZoneName(String tzId) { - String ucTzId = IntlUtil.toUpperCase(tzId); - String canTzId = canonicalTimeZoneIDMap.get().get(ucTzId); - if (canTzId == null) { - return null; - } - if (canTzId.equals("Etc/UTC") || canTzId.equals("Etc/GMT")) { - return "UTC"; - } else { - return canTzId; - } + Pair result = getAvailableNamedTimeZoneIdentifier(tzId); + return (result == null) ? null : result.getSecond(); } @TruffleBoundary - public static String canonicalizeTimeZoneName(TruffleString tzId) { - return canonicalizeTimeZoneName(Strings.toJavaString(tzId)); + public static Pair getAvailableNamedTimeZoneIdentifier(String tzId) { + String ucTzId = IntlUtil.toUpperCase(tzId); + return canonicalTimeZoneIDMap.get().get(ucTzId); } private static boolean containsOneOf(String suspect, String containees) { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java index 80e71eb071f..aa81e5155fe 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/util/TemporalUtil.java @@ -1248,16 +1248,15 @@ public static JSTemporalTimeZoneObject createTemporalTimeZone(JSContext ctx, JSR newIdentifier = formatTimeZoneOffsetString(result); offsetNs = BigInt.valueOf(result); } else { - assert canonicalizeTimeZoneName(identifier).equals(identifier) : identifier; offsetNs = null; } return JSTemporalTimeZone.create(ctx, realm, proto, offsetNs, newIdentifier); } @TruffleBoundary - public static TruffleString canonicalizeTimeZoneName(TruffleString timeZone) { - String tzId = JSDateTimeFormat.canonicalizeTimeZoneName(timeZone); - return tzId == null ? null : Strings.fromJavaString(tzId); + public static Pair getAvailableNamedTimeZoneIdentifier(TruffleString timeZone) { + Pair pair = JSDateTimeFormat.getAvailableNamedTimeZoneIdentifier(Strings.toJavaString(timeZone)); + return (pair == null) ? null : new Pair<>(Strings.fromJavaString(pair.getFirst()), Strings.fromJavaString(pair.getSecond())); } @TruffleBoundary @@ -3143,13 +3142,33 @@ public static BigInt interpretISODateTimeOffset(JSContext ctx, JSRealm realm, in return instant.getNanoseconds(); } - public static boolean timeZoneEquals(Object tz1, Object tz2, ToTemporalTimeZoneIdentifierNode toTimeZoneIdentifier) { - if (tz1 == tz2) { + public static boolean timeZoneEquals(Object one, Object two, ToTemporalTimeZoneIdentifierNode toTimeZoneIdentifier) { + if (one == two) { + return true; + } + TruffleString timeZoneOne = toTimeZoneIdentifier.executeString(one); + TruffleString timeZoneTwo = toTimeZoneIdentifier.executeString(two); + if (Boundaries.equals(timeZoneOne, timeZoneTwo)) { return true; + } else { + boolean numOffsetOne = canParseAsTimeZoneNumericUTCOffset(timeZoneOne); + boolean numOffsetTwo = canParseAsTimeZoneNumericUTCOffset(timeZoneTwo); + if (numOffsetOne) { + if (numOffsetTwo) { + return parseTimeZoneOffsetString(timeZoneOne) == parseTimeZoneOffsetString(timeZoneTwo); + } else { + return false; + } + } else { + if (numOffsetTwo) { + return false; + } else { + TruffleString primaryOne = getAvailableNamedTimeZoneIdentifier(timeZoneOne).getSecond(); + TruffleString primaryTwo = getAvailableNamedTimeZoneIdentifier(timeZoneTwo).getSecond(); + return Boundaries.equals(primaryOne, primaryTwo); + } + } } - TruffleString s1 = toTimeZoneIdentifier.executeString(tz1); - TruffleString s2 = toTimeZoneIdentifier.executeString(tz2); - return Boundaries.equals(s1, s2); } public static Object consolidateCalendars(Object one, Object two, ToTemporalCalendarIdentifierNode toCalendarIdentifier) { From 173ec09ac12836ecf752d76ed0d77bd5990090a0 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Thu, 5 Sep 2024 12:55:39 +0200 Subject: [PATCH 223/265] Updating the status of Test262 test-suite. --- graal-js/test/test262.json | 36 ++++-------------------------------- 1 file changed, 4 insertions(+), 32 deletions(-) diff --git a/graal-js/test/test262.json b/graal-js/test/test262.json index b667f0b462a..3f5d2599eed 100644 --- a/graal-js/test/test262.json +++ b/graal-js/test/test262.json @@ -3407,18 +3407,10 @@ "filePath" : "intl402/Temporal/ZonedDateTime/etc-timezone.js", "status" : "FAIL", "comment" : "new failures 2024-08-09" - }, { - "filePath" : "intl402/Temporal/ZonedDateTime/from/argument-valid.js", - "status" : "FAIL", - "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/ZonedDateTime/from/canonicalize-calendar.js", "status" : "FAIL", "comment" : "new failures 2024-08-09" - }, { - "filePath" : "intl402/Temporal/ZonedDateTime/from/do-not-canonicalize-iana-identifiers.js", - "status" : "FAIL", - "comment" : "new failures 2023-10-09" }, { "filePath" : "intl402/Temporal/ZonedDateTime/from/etc-timezone.js", "status" : "FAIL", @@ -3443,34 +3435,14 @@ "filePath" : "intl402/Temporal/ZonedDateTime/legacy-non-iana.js", "status" : "FAIL", "comment" : "new failures 2024-08-09" - }, { - "filePath" : "intl402/Temporal/ZonedDateTime/links-africa.js", - "status" : "FAIL", - "comment" : "new failures 2024-08-09" - }, { - "filePath" : "intl402/Temporal/ZonedDateTime/links-asia.js", - "status" : "FAIL", - "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/ZonedDateTime/links-backward.js", "status" : "FAIL", "comment" : "new failures 2024-08-09" - }, { - "filePath" : "intl402/Temporal/ZonedDateTime/links-backzone.js", - "status" : "FAIL", - "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/ZonedDateTime/links-etcetera.js", "status" : "FAIL", "comment" : "new failures 2024-08-09" - }, { - "filePath" : "intl402/Temporal/ZonedDateTime/links-europe.js", - "status" : "FAIL", - "comment" : "new failures 2024-08-09" - }, { - "filePath" : "intl402/Temporal/ZonedDateTime/links-northamerica.js", - "status" : "FAIL", - "comment" : "new failures 2024-08-09" }, { "filePath" : "intl402/Temporal/ZonedDateTime/non-canonical-utc.js", "status" : "FAIL", @@ -3575,6 +3547,10 @@ "filePath" : "intl402/Temporal/ZonedDateTime/prototype/toLocaleString/options-undefined.js", "status" : "FAIL", "comment" : "Temporal failures" + }, { + "filePath" : "intl402/Temporal/ZonedDateTime/prototype/toLocaleString/time-zone-canonicalized.js", + "status" : "FAIL", + "comment" : "Obsolete test: expects canonical timezones to be observable." }, { "filePath" : "intl402/Temporal/ZonedDateTime/prototype/until/canonicalize-calendar.js", "status" : "FAIL", @@ -3611,10 +3587,6 @@ "filePath" : "intl402/Temporal/ZonedDateTime/timezone-case-insensitive.js", "status" : "FAIL", "comment" : "new failures 2024-08-09" - }, { - "filePath" : "intl402/Temporal/ZonedDateTime/timezone-ids-basic.js", - "status" : "FAIL", - "comment" : "new failures 2024-08-09" }, { "filePath" : "language/comments/S7.4_A5.js", "status" : "PASS", From 2a26d91f44d29987059d4951d8d573142d192e16 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 4 Sep 2024 16:08:41 +0200 Subject: [PATCH 224/265] Make js.webassembly option stable and allowed in sandboxed mode. --- .../src/com/oracle/truffle/js/runtime/JSContextOptions.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java index 188e6a5e8f3..10767404645 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java @@ -540,7 +540,7 @@ public Map apply(String value) { @CompilationFinal private boolean useUTCForLegacyDates; public static final String WEBASSEMBLY_NAME = JS_OPTION_PREFIX + "webassembly"; - @Option(name = WEBASSEMBLY_NAME, category = OptionCategory.EXPERT, help = "Enable WebAssembly JavaScript API.") // + @Option(name = WEBASSEMBLY_NAME, category = OptionCategory.USER, stability = OptionStability.STABLE, help = "Enable WebAssembly JavaScript API.") // public static final OptionKey WEBASSEMBLY = new OptionKey<>(false); @CompilationFinal private boolean webAssembly; From 5d508c103db4c2ec4bf731ac8b5b59b9c0c5655b Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Wed, 4 Sep 2024 16:13:59 +0200 Subject: [PATCH 225/265] Update changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 76cb7044aed..0ce227a3169 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ See [release calendar](https://www.graalvm.org/release-calendar/) for release da * Implemented the [`Promise.try`](https://github.com/tc39/proposal-promise-try) proposal. It is available in ECMAScript staging mode (`--js.ecmascript-version=staging`). * Implemented the [Source Phase Imports](https://github.com/tc39/proposal-source-phase-imports) proposal. It is available behind the experimental option (`--js.source-phase-imports`). * Added option `js.stack-trace-api` that enables/disables `Error.captureStackTrace`, `Error.prepareStackTrace` and `Error.stackTraceLimit`. These non-standard extensions are disabled by default (unless `js.v8-compat` or `js.nashorn-compat` is used). +* Made option `js.webassembly` stable. ## Version 24.1.0 * ECMAScript 2024 mode/features enabled by default. From 3451eed42589f5a06fd9abba2c74aa37e35635c8 Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 6 Sep 2024 21:07:30 +0000 Subject: [PATCH 226/265] Update graal import. --- graal-js/mx.graal-js/suite.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graal-js/mx.graal-js/suite.py b/graal-js/mx.graal-js/suite.py index 1e881a5afb8..2b2b2a0c672 100644 --- a/graal-js/mx.graal-js/suite.py +++ b/graal-js/mx.graal-js/suite.py @@ -24,7 +24,7 @@ { "name" : "regex", "subdir" : True, - "version" : "f4676a7a75e64e7ef2333f2f3f070a58b93eefe2", + "version" : "fbe83654ccdd082a8d470aa59b180fad9b4cc8c6", "urls" : [ {"url" : "https://github.com/oracle/graal.git", "kind" : "git"}, ] From 64600c21b2c330d3182b19cd6c2802016fbfcecd Mon Sep 17 00:00:00 2001 From: ol-automation_ww Date: Fri, 6 Sep 2024 21:07:30 +0000 Subject: [PATCH 227/265] Sync CI files. --- common.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/common.json b/common.json index 467c4edfdcc..2f13f48c648 100644 --- a/common.json +++ b/common.json @@ -4,11 +4,11 @@ "Jsonnet files should not include this file directly but use ci/common.jsonnet instead." ], - "mx_version": "7.29.5", + "mx_version": "7.29.6", "COMMENT.jdks": "When adding or removing JDKs keep in sync with JDKs in ci/common.jsonnet", "jdks": { - "galahad-jdk": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+12-1236", "platformspecific": true, "extrabundles": ["static-libs"]}, + "galahad-jdk": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+13-1404", "platformspecific": true, "extrabundles": ["static-libs"]}, "oraclejdk11": {"name": "jpg-jdk", "version": "11.0.11", "build_id": "jdk-11.0.11+9", "platformspecific": true, "extrabundles": ["static-libs"] }, @@ -45,13 +45,13 @@ "labsjdk-ee-21-llvm": {"name": "labsjdk", "version": "ee-21.0.2+13-jvmci-23.1-b33-sulong", "platformspecific": true }, "graalvm-ee-21": {"name": "graalvm-java21", "version": "23.1.3", "platformspecific": true }, - "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+12", "platformspecific": true, "extrabundles": ["static-libs"]}, - "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+12-jvmci-b01", "platformspecific": true }, - "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+12-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+12-jvmci-b01-sulong", "platformspecific": true }, - "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+12-jvmci-b01", "platformspecific": true }, - "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+12-jvmci-b01-debug", "platformspecific": true }, - "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+12-jvmci-b01-sulong", "platformspecific": true } + "oraclejdk-latest": {"name": "jpg-jdk", "version": "24", "build_id": "jdk-24+13", "platformspecific": true, "extrabundles": ["static-libs"]}, + "labsjdk-ce-latest": {"name": "labsjdk", "version": "ce-24+13-jvmci-b01", "platformspecific": true }, + "labsjdk-ce-latestDebug": {"name": "labsjdk", "version": "ce-24+13-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ce-latest-llvm": {"name": "labsjdk", "version": "ce-24+13-jvmci-b01-sulong", "platformspecific": true }, + "labsjdk-ee-latest": {"name": "labsjdk", "version": "ee-24+13-jvmci-b01", "platformspecific": true }, + "labsjdk-ee-latestDebug": {"name": "labsjdk", "version": "ee-24+13-jvmci-b01-debug", "platformspecific": true }, + "labsjdk-ee-latest-llvm": {"name": "labsjdk", "version": "ee-24+13-jvmci-b01-sulong", "platformspecific": true } }, "eclipse": { From cabe6a68f1c406322c83df222b2d4d7077050832 Mon Sep 17 00:00:00 2001 From: Andreas Woess Date: Sat, 7 Sep 2024 01:41:18 +0200 Subject: [PATCH 228/265] [GR-57953] Set --enable-native-access=org.graalvm.truffle[.runtime] in node launcher. --- graal-nodejs/deps/v8/src/graal/graal_isolate.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/graal-nodejs/deps/v8/src/graal/graal_isolate.cc b/graal-nodejs/deps/v8/src/graal/graal_isolate.cc index acb0b86dd14..90b74c3d135 100644 --- a/graal-nodejs/deps/v8/src/graal/graal_isolate.cc +++ b/graal-nodejs/deps/v8/src/graal/graal_isolate.cc @@ -530,6 +530,9 @@ v8::Isolate* GraalIsolate::New(v8::Isolate::CreateParams const& params, v8::Isol // Set process name (it would be shown in jcmd, jps) options.push_back({const_cast("-Dsun.java.command=node"), nullptr}); + options.push_back({const_cast("--enable-native-access=org.graalvm.truffle"), nullptr}); + options.push_back({const_cast("--enable-native-access=org.graalvm.truffle.runtime"), nullptr}); // GR-57817 + #if defined(DEBUG) std::string debugPort = getstdenv("DEBUG_PORT"); std::string debugParam; From 795f49245e1616d3df92cbd523d91f8913020d01 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Mon, 9 Sep 2024 13:12:50 +0200 Subject: [PATCH 229/265] Removing the obsolete handling of extra arguments of internal scripts. --- graal-nodejs/lib/inspector.js | 2 +- graal-nodejs/lib/internal/graal/buffer.js | 2 +- graal-nodejs/lib/internal/graal/debug.js | 4 +--- graal-nodejs/lib/internal/main/worker_thread.js | 2 +- graal-nodejs/lib/internal/worker/io.js | 2 +- .../oracle/truffle/trufflenode/GraalJSAccess.java | 13 ------------- 6 files changed, 5 insertions(+), 20 deletions(-) diff --git a/graal-nodejs/lib/inspector.js b/graal-nodejs/lib/inspector.js index 872c27c822c..e4f5169f0e6 100644 --- a/graal-nodejs/lib/inspector.js +++ b/graal-nodejs/lib/inspector.js @@ -194,7 +194,7 @@ module.exports = { }; // Use the mockup provided by 'inspect' instrument -const graalExport = typeof graalExtension === 'undefined' ? arguments[arguments.length - 1] : graalExtension; +const graalExport = graalExtension; if (graalExport) { // The object provided by 'inspect' instrument is a foreign object. // This breaks some use-cases (insertion into WeakMap) diff --git a/graal-nodejs/lib/internal/graal/buffer.js b/graal-nodejs/lib/internal/graal/buffer.js index 95bc729cdfd..6398c9d851f 100644 --- a/graal-nodejs/lib/internal/graal/buffer.js +++ b/graal-nodejs/lib/internal/graal/buffer.js @@ -40,7 +40,7 @@ */ // When NIO buffers are enabled, GraalJSAccess ensures that this module is loaded with the builtins constructor as extra argument. -const NIOBufferPrototypeAllocator = typeof graalExtension === 'undefined' ? arguments[arguments.length - 1] : graalExtension; +const NIOBufferPrototypeAllocator = graalExtension; function patchBufferPrototype(proto) { if (NIOBufferPrototypeAllocator) { diff --git a/graal-nodejs/lib/internal/graal/debug.js b/graal-nodejs/lib/internal/graal/debug.js index 1e757dff794..e2a8b89e51e 100644 --- a/graal-nodejs/lib/internal/graal/debug.js +++ b/graal-nodejs/lib/internal/graal/debug.js @@ -39,8 +39,6 @@ * SOFTWARE. */ -const setBreakPoint = typeof graalExtension === 'undefined' ? arguments[arguments.length - 1] : graalExtension; - module.exports = { - setBreakPoint: setBreakPoint + setBreakPoint: graalExtension }; diff --git a/graal-nodejs/lib/internal/main/worker_thread.js b/graal-nodejs/lib/internal/main/worker_thread.js index 99376ca674d..c877605cbca 100644 --- a/graal-nodejs/lib/internal/main/worker_thread.js +++ b/graal-nodejs/lib/internal/main/worker_thread.js @@ -24,7 +24,7 @@ const { } = require('internal/process/pre_execution'); // Passed by Graal.js init phase during global module loading. -const SharedMemMessagingInit = typeof graalExtension === 'undefined' ? arguments[arguments.length - 1] : graalExtension; +const SharedMemMessagingInit = graalExtension; if (!SharedMemMessagingInit) { throw new Error("Fatal: cannot initialize Worker"); } diff --git a/graal-nodejs/lib/internal/worker/io.js b/graal-nodejs/lib/internal/worker/io.js index 34eebaf92d8..9d2b9400f81 100644 --- a/graal-nodejs/lib/internal/worker/io.js +++ b/graal-nodejs/lib/internal/worker/io.js @@ -568,7 +568,7 @@ module.exports = { // ##### Graal.js Java interop messages handling // Passed by Graal.js init phase during global module loading. -const SharedMemMessagingInit = typeof graalExtension === 'undefined' ? arguments[arguments.length - 1] : graalExtension; +const SharedMemMessagingInit = graalExtension; if (!SharedMemMessagingInit) { throw new Error("Fatal: cannot initialize Worker"); } diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java index 5cdeff86fd6..c9432cc6613 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java @@ -2320,19 +2320,6 @@ private static Object getExtraArgumentOfInternalScript(TruffleString moduleName, return extraArgument; } - @TruffleBoundary - private static Object[] getInternalModuleUserArguments(Object[] args, TruffleString moduleName, JSRealm realm) { - Object[] userArgs = JSArguments.extractUserArguments(args); - Object extraArgument = getExtraArgumentOfInternalScript(moduleName, realm); - if (extraArgument == null) { - return userArgs; - } - Object[] extendedArgs = new Object[userArgs.length + 1]; - System.arraycopy(userArgs, 0, extendedArgs, 0, userArgs.length); - extendedArgs[userArgs.length] = extraArgument; - return extendedArgs; - } - public Object scriptGetUnboundScript(Object script) { return new UnboundScript((Script) script); } From d983d9cfc0df9106428526b3e48a19c53498970d Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Mon, 9 Sep 2024 13:56:49 +0200 Subject: [PATCH 230/265] Adding an experimental executor for the event loop thread. --- graal-nodejs/deps/v8/src/graal/callbacks.cc | 19 ++++++ graal-nodejs/deps/v8/src/graal/callbacks.h | 2 + .../deps/v8/src/graal/graal_isolate.cc | 5 ++ .../deps/v8/src/graal/graal_isolate.h | 2 + graal-nodejs/lib/graal.js | 47 ++++++++++++++ .../org.graalvm.nodejs/jni-config.json | 4 +- .../org.graalvm.nodejs/reflect-config.json | 6 ++ .../trufflenode/EventLoopExecutor.java | 62 +++++++++++++++++++ .../truffle/trufflenode/GraalJSAccess.java | 18 +++++- .../truffle/trufflenode/NativeAccess.java | 2 + .../truffle/trufflenode/NodeJSAgent.java | 4 ++ 11 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 graal-nodejs/lib/graal.js create mode 100644 graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/EventLoopExecutor.java diff --git a/graal-nodejs/deps/v8/src/graal/callbacks.cc b/graal-nodejs/deps/v8/src/graal/callbacks.cc index 197bb9c5025..7d2c644dee2 100644 --- a/graal-nodejs/deps/v8/src/graal/callbacks.cc +++ b/graal-nodejs/deps/v8/src/graal/callbacks.cc @@ -127,6 +127,7 @@ static const JNINativeMethod callbacks[] = { CALLBACK("executeInterruptCallback", "(JJ)V", &GraalExecuteInterruptCallback), CALLBACK("notifyWasmStreamingCallback", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V", &GraalNotifyWasmStreamingCallback), CALLBACK("postWakeUpTask", "(J)V", &GraalPostWakeUpTask), + CALLBACK("postRunnableTask", "(JLjava/lang/Object;)V", &GraalPostRunnableTask), }; static const int CALLBACK_COUNT = sizeof(callbacks) / sizeof(*callbacks); @@ -931,3 +932,21 @@ void GraalPostWakeUpTask(JNIEnv* env, jclass nativeAccess, jlong taskRunnerPoint std::unique_ptr task = std::make_unique(); reinterpret_cast (taskRunnerPointer)->PostNonNestableTask(std::move(task)); } + +class RunnableTask : public v8::Task { +public: + RunnableTask(jobject runnable) : runnable_(runnable) {}; + void Run() { + GraalIsolate* isolate = CurrentIsolateChecked(); + isolate->ExecuteRunnable(runnable_); + isolate->GetJNIEnv()->DeleteGlobalRef(runnable_); + runnable_ = nullptr; + }; +private: + jobject runnable_; +}; + +void GraalPostRunnableTask(JNIEnv* env, jclass nativeAccess, jlong taskRunnerPointer, jobject runnable) { + std::unique_ptr task = std::make_unique(env->NewGlobalRef(runnable)); + reinterpret_cast (taskRunnerPointer)->PostNonNestableTask(std::move(task)); +} diff --git a/graal-nodejs/deps/v8/src/graal/callbacks.h b/graal-nodejs/deps/v8/src/graal/callbacks.h index 37f7b384636..25d033f76c0 100644 --- a/graal-nodejs/deps/v8/src/graal/callbacks.h +++ b/graal-nodejs/deps/v8/src/graal/callbacks.h @@ -166,4 +166,6 @@ void GraalNotifyWasmStreamingCallback(JNIEnv* env, jclass nativeAccess, jobject void GraalPostWakeUpTask(JNIEnv* env, jclass nativeAccess, jlong taskRunnerPointer); +void GraalPostRunnableTask(JNIEnv* env, jclass nativeAccess, jlong taskRunnerPointer, jobject runnable); + #endif /* CALLBACKS_H_ */ diff --git a/graal-nodejs/deps/v8/src/graal/graal_isolate.cc b/graal-nodejs/deps/v8/src/graal/graal_isolate.cc index 90b74c3d135..792a6924288 100644 --- a/graal-nodejs/deps/v8/src/graal/graal_isolate.cc +++ b/graal-nodejs/deps/v8/src/graal/graal_isolate.cc @@ -846,6 +846,7 @@ GraalIsolate::GraalIsolate(JavaVM* jvm, JNIEnv* env, v8::Isolate::CreateParams c ACCESS_METHOD(GraalAccessMethod::isolate_schedule_pause_on_next_statement, "isolateSchedulePauseOnNextStatement", "()V") ACCESS_METHOD(GraalAccessMethod::isolate_measure_memory, "isolateMeasureMemory", "(Ljava/lang/Object;Z)V") ACCESS_METHOD(GraalAccessMethod::isolate_set_task_runner, "isolateSetTaskRunner", "(J)V") + ACCESS_METHOD(GraalAccessMethod::isolate_execute_runnable, "isolateExecuteRunnable", "(Ljava/lang/Object;)V") ACCESS_METHOD(GraalAccessMethod::template_set, "templateSet", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;I)V") ACCESS_METHOD(GraalAccessMethod::template_set_accessor_property, "templateSetAccessorProperty", "(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;I)V") ACCESS_METHOD(GraalAccessMethod::object_template_new, "objectTemplateNew", "(Ljava/lang/Object;)Ljava/lang/Object;") @@ -1643,3 +1644,7 @@ void GraalIsolate::SetTaskRunner(std::shared_ptr task_runner) { this->task_runner_ = task_runner; JNI_CALL_VOID(this, GraalAccessMethod::isolate_set_task_runner, (jlong) task_runner.get()); } + +void GraalIsolate::ExecuteRunnable(jobject runnable) { + JNI_CALL_VOID(this, GraalAccessMethod::isolate_execute_runnable, runnable); +} diff --git a/graal-nodejs/deps/v8/src/graal/graal_isolate.h b/graal-nodejs/deps/v8/src/graal/graal_isolate.h index 49155255595..19b15fd0b9e 100644 --- a/graal-nodejs/deps/v8/src/graal/graal_isolate.h +++ b/graal-nodejs/deps/v8/src/graal/graal_isolate.h @@ -227,6 +227,7 @@ enum GraalAccessMethod { isolate_schedule_pause_on_next_statement, isolate_measure_memory, isolate_set_task_runner, + isolate_execute_runnable, template_set, template_set_accessor_property, object_template_new, @@ -472,6 +473,7 @@ class GraalIsolate { void Exit(); void HandleEmptyCallResult(); void EnqueueMicrotask(v8::Local microtask); + void ExecuteRunnable(jobject runnable); enum GCCallbackType { kIsolateGCCallbackType = 0, diff --git a/graal-nodejs/lib/graal.js b/graal-nodejs/lib/graal.js new file mode 100644 index 00000000000..e3143a5ddd9 --- /dev/null +++ b/graal-nodejs/lib/graal.js @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +// This module provides an experimental eventLoopExecutor i.e. an instance of +// java.util.concurrent.Executor that executes runnables in the event loop thread. + +module.exports = { + eventLoopExecutor: graalExtension, +}; diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/META-INF/native-image/org.graalvm.nodejs/jni-config.json b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/META-INF/native-image/org.graalvm.nodejs/jni-config.json index b18f63da69b..30178a6e09e 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/META-INF/native-image/org.graalvm.nodejs/jni-config.json +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/META-INF/native-image/org.graalvm.nodejs/jni-config.json @@ -99,6 +99,7 @@ { "name": "isolateEnqueueMicrotask" }, { "name": "isolateEnter" }, { "name": "isolateEnterPolyglotEngine" }, + { "name": "isolateExecuteRunnable" }, { "name": "isolateExit" }, { "name": "isolateGetDoublePlaceholder" }, { "name": "isolateGetHeapStatistics" }, @@ -363,7 +364,8 @@ { "name": "getWasmModuleTransferId" }, { "name": "getWasmModuleFromId" }, { "name": "notifyWasmStreamingCallback" }, - { "name": "postWakeUpTask" } + { "name": "postWakeUpTask" }, + { "name": "postRunnableTask" } ] }, { diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/META-INF/native-image/org.graalvm.nodejs/reflect-config.json b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/META-INF/native-image/org.graalvm.nodejs/reflect-config.json index 5d6b063e1f4..878d4ff8a73 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/META-INF/native-image/org.graalvm.nodejs/reflect-config.json +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/META-INF/native-image/org.graalvm.nodejs/reflect-config.json @@ -4,5 +4,11 @@ "methods" : [ { "name" : "getProperty", "parameterTypes" : ["java.lang.String"] } ] + }, + { + "name" : "com.oracle.truffle.trufflenode.EventLoopExecutor", + "methods" : [ + { "name" : "execute", "parameterTypes" : ["java.lang.Runnable"] } + ] } ] diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/EventLoopExecutor.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/EventLoopExecutor.java new file mode 100644 index 00000000000..c89370c0e10 --- /dev/null +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/EventLoopExecutor.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.trufflenode; + +import java.util.Objects; +import java.util.concurrent.Executor; + +/** + * Executor that runs the given runnable in the event loop thread. + */ +public class EventLoopExecutor implements Executor { + private final NodeJSAgent agent; + + EventLoopExecutor(NodeJSAgent agent) { + this.agent = agent; + } + + @Override + public void execute(Runnable runnable) { + Objects.requireNonNull(runnable); + NativeAccess.postRunnableTask(agent.getTaskRunnerPointer(), runnable); + } + +} diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java index c9432cc6613..2271f31dc4b 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java @@ -306,6 +306,7 @@ public final class GraalJSAccess { public static final TruffleString NODE_INTERNAL_GRAAL_WASM = Strings.constant("node:internal/graal/wasm"); public static final TruffleString NODE_INTERNAL_WORKER_IO = Strings.constant("node:internal/worker/io"); public static final TruffleString NODE_INTERNAL_MAIN_WORKER_THREAD = Strings.constant("node:internal/main/worker_thread"); + public static final TruffleString NODE_GRAAL = Strings.constant("node:graal"); public static final TruffleString NODE_INSPECTOR = Strings.constant("node:inspector"); public static final TruffleString DOT_JS = Strings.constant(".js"); public static final TruffleString SHEBANG = Strings.constant("#!"); @@ -2294,7 +2295,7 @@ public Object scriptRun(Object script) { } } - private static Object getExtraArgumentOfInternalScript(TruffleString moduleName, JSRealm realm) { + private Object getExtraArgumentOfInternalScript(TruffleString moduleName, JSRealm realm) { Object extraArgument = null; JSContext context = realm.getContext(); if (NIO_BUFFER_MODULE_NAME.equals(moduleName)) { @@ -2316,6 +2317,8 @@ private static Object getExtraArgumentOfInternalScript(TruffleString moduleName, extraArgument = (inspector == null) ? Null.instance : inspector; } else if (NODE_INTERNAL_GRAAL_WASM.equals(moduleName)) { extraArgument = createWasmStreamingCallback(realm); + } else if (NODE_GRAAL.equals(moduleName)) { + extraArgument = createEventLoopExecutor(); } return extraArgument; } @@ -4168,6 +4171,19 @@ private static void notifyWasmStreamingCallback(Object response, Object resolve, NativeAccess.notifyWasmStreamingCallback(response, resolve, reject); } + private Object createEventLoopExecutor() { + return mainJSRealm.getEnv().asGuestValue(new EventLoopExecutor(agent)); + } + + public void isolateExecuteRunnable(Object runnable) { + try { + ((Runnable) runnable).run(); + } catch (Exception ex) { + ex.printStackTrace(); + System.exit(1); + } + } + public static class WeakCallback extends WeakReference { long data; diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/NativeAccess.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/NativeAccess.java index 2819dc2f14f..06d0b54d793 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/NativeAccess.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/NativeAccess.java @@ -174,4 +174,6 @@ public static native Object executePropertyHandlerDefiner(long functionPointer, public static native void postWakeUpTask(long taskRunnerPointer); + public static native void postRunnableTask(long taskRunnerPointer, Object runnable); + } diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/NodeJSAgent.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/NodeJSAgent.java index b826168ceba..09d48b9062b 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/NodeJSAgent.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/NodeJSAgent.java @@ -63,6 +63,10 @@ void setTaskRunnerPointer(long taskRunnerPointer) { this.taskRunnerPointer = taskRunnerPointer; } + long getTaskRunnerPointer() { + return taskRunnerPointer; + } + @Override public void wake() { NativeAccess.postWakeUpTask(taskRunnerPointer); From 49d3a0ad3c6fcd81d3ef90195b41aff33ee814c5 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Mon, 9 Sep 2024 15:52:49 +0200 Subject: [PATCH 231/265] Event loop executor should check if the event loop is still alive. --- .../com/oracle/truffle/trufflenode/EventLoopExecutor.java | 8 +++++++- .../src/com/oracle/truffle/trufflenode/GraalJSAccess.java | 1 + .../src/com/oracle/truffle/trufflenode/NodeJSAgent.java | 4 ++-- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/EventLoopExecutor.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/EventLoopExecutor.java index c89370c0e10..170a237e9c2 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/EventLoopExecutor.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/EventLoopExecutor.java @@ -56,7 +56,13 @@ public class EventLoopExecutor implements Executor { @Override public void execute(Runnable runnable) { Objects.requireNonNull(runnable); - NativeAccess.postRunnableTask(agent.getTaskRunnerPointer(), runnable); + synchronized (agent) { + long taskRunnerPointer = agent.getTaskRunnerPointer(); + if (taskRunnerPointer == 0) { + throw new IllegalStateException("Event loop of this executor has been terminated already!"); + } + NativeAccess.postRunnableTask(taskRunnerPointer, runnable); + } } } diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java index 2271f31dc4b..11f7aa3106d 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java @@ -3217,6 +3217,7 @@ public Object isolateGetDoublePlaceholder() { } public void isolateDispose(boolean exit, int status) { + agent.setTaskRunnerPointer(0); if (exit) { exit(status); } diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/NodeJSAgent.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/NodeJSAgent.java index 09d48b9062b..cfc449802b4 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/NodeJSAgent.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/NodeJSAgent.java @@ -59,11 +59,11 @@ Thread getThread() { return thread; } - void setTaskRunnerPointer(long taskRunnerPointer) { + synchronized void setTaskRunnerPointer(long taskRunnerPointer) { this.taskRunnerPointer = taskRunnerPointer; } - long getTaskRunnerPointer() { + synchronized long getTaskRunnerPointer() { return taskRunnerPointer; } From 0738a9c44fc9ad55a929c8d1d5edf7fa5632c0cd Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Mon, 9 Sep 2024 16:10:41 +0200 Subject: [PATCH 232/265] Basic tests of eventLoopExecutor. --- .../test/EventLoopExecutorTest.java | 90 ++++++++++++++ .../mx.graal-nodejs/mx_graal_nodejs.py | 4 +- .../test/graal/unit/eventLoopExecutor.js | 114 ++++++++++++++++++ 3 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode.test/src/com/oracle/truffle/trufflenode/test/EventLoopExecutorTest.java create mode 100644 graal-nodejs/test/graal/unit/eventLoopExecutor.js diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode.test/src/com/oracle/truffle/trufflenode/test/EventLoopExecutorTest.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode.test/src/com/oracle/truffle/trufflenode/test/EventLoopExecutorTest.java new file mode 100644 index 00000000000..caacadd9e17 --- /dev/null +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode.test/src/com/oracle/truffle/trufflenode/test/EventLoopExecutorTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.trufflenode.test; + +import java.util.concurrent.Executor; + +import org.graalvm.polyglot.Value; + +/** + * Helper class for tests of eventLoopExecutor. + */ +public class EventLoopExecutorTest { + + public static boolean testNullRunnable(Executor executor) { + try { + executor.execute(null); + return false; + } catch (NullPointerException npe) { + return true; + } + } + + public static void testAsyncResolution(Executor executor, Value resolve) { + new Thread(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(1000); + } catch (InterruptedException iex) { + } + // cannot call resolve.execute(42) directly because we are in the wrong thread, + // we have to do it in the event loop thread + executor.execute(() -> resolve.execute(42)); + } + }).start(); + } + + public static boolean testFinishedEventLoop(Executor executor) { + try { + executor.execute(new Runnable() { + @Override + public void run() { + System.exit(1); // should not be reached + } + }); + return false; + } catch (IllegalStateException isex) { + return true; + } + } + +} diff --git a/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py b/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py index ccd97b2d790..963f6922e4e 100644 --- a/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py +++ b/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py @@ -56,8 +56,8 @@ def _graal_nodejs_post_gate_runner(args, tasks): _setEnvVar('NODE_INTERNAL_ERROR_CHECK', 'true') with Task('UnitTests', tasks, tags=[GraalNodeJsTags.allTests, GraalNodeJsTags.unitTests, GraalNodeJsTags.coverage], report=True) as t: if t: - mx.command_function('build')(['--dependencies', 'TRUFFLE_JS_TESTS']) - _setEnvVar('NODE_JVM_CLASSPATH', mx.distribution('graal-js:TRUFFLE_JS_TESTS').path) + mx.command_function('build')(['--dependencies', 'TRUFFLE_JS_TESTS,TRUFFLENODE_TEST']) + _setEnvVar('NODE_JVM_CLASSPATH', mx.classpath(['graal-js:TRUFFLE_JS_TESTS', 'graal-nodejs:TRUFFLENODE_TEST'])) commonArgs = ['-ea', '-esa'] unitTestDir = join(_suite.dir, 'test', 'graal') for dir_name in 'node_modules', 'build': diff --git a/graal-nodejs/test/graal/unit/eventLoopExecutor.js b/graal-nodejs/test/graal/unit/eventLoopExecutor.js new file mode 100644 index 00000000000..5fc888cccf2 --- /dev/null +++ b/graal-nodejs/test/graal/unit/eventLoopExecutor.js @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2024, 2024, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +const assert = require('assert'); +const unitTest = require('./_unit'); + +const { + Worker, + isMainThread +} = require('worker_threads'); + +describe('eventLoopExecutor', function () { + if (unitTest.hasJavaInterop()) { + const eventLoopExecutor = require('node:graal').eventLoopExecutor; + const EventLoopExecutorTest = Java.type('com.oracle.truffle.trufflenode.test.EventLoopExecutorTest'); + + it('refuses null Runnable', function () { + assert.ok(EventLoopExecutorTest.testNullRunnable(eventLoopExecutor)); + }); + + it('allows asynchronous resolution of promises', function (done) { + const { promise, resolve } = Promise.withResolvers(); + promise.then(result => { + assert.strictEqual(result, 42); + done(); + }); + EventLoopExecutorTest.testAsyncResolution(eventLoopExecutor, resolve); + }).timeout(5000); + + it('works in a worker', function (done) { + const w = new Worker(` + const { + parentPort + } = require('worker_threads'); + const assert = require('assert'); + + const { promise, resolve } = Promise.withResolvers(); + promise.then(result => { + assert.strictEqual(result, 42); + parentPort.postMessage('done'); + }); + + // keep the Worker alive + parentPort.on('message', (m) => assert.fail('Unexpected message: ' + m)); + + const eventLoopExecutor = require('node:graal').eventLoopExecutor; + const EventLoopExecutorTest = Java.type('com.oracle.truffle.trufflenode.test.EventLoopExecutorTest'); + EventLoopExecutorTest.testAsyncResolution(eventLoopExecutor, resolve);`, + { + eval: true + }); + w.on('message', () => { + w.terminate().then(()=>{done()}); + }); + }).timeout(5000); + + it('refuses to post to a terminated worker', function (done) { + const w = new Worker(` + const { + parentPort + } = require('worker_threads'); + + const eventLoopExecutor = require('node:graal').eventLoopExecutor; + parentPort.postMessage(eventLoopExecutor);`, + { + eval: true + }); + w.on('message', (workerExecutor) => { + w.terminate().then(() => { + assert.ok(EventLoopExecutorTest.testFinishedEventLoop(workerExecutor)); + done(); + }); + }); + }).timeout(5000); + } +}); From b9e065a2211a4314f1c8646bf6005e6a612f7a58 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Mon, 9 Sep 2024 16:33:46 +0200 Subject: [PATCH 233/265] Adding a note about eventLoopExecutor into change-log. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ce227a3169..5d6574894a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ See [release calendar](https://www.graalvm.org/release-calendar/) for release da * Implemented the [Source Phase Imports](https://github.com/tc39/proposal-source-phase-imports) proposal. It is available behind the experimental option (`--js.source-phase-imports`). * Added option `js.stack-trace-api` that enables/disables `Error.captureStackTrace`, `Error.prepareStackTrace` and `Error.stackTraceLimit`. These non-standard extensions are disabled by default (unless `js.v8-compat` or `js.nashorn-compat` is used). * Made option `js.webassembly` stable. +* Added an experimental `java.util.concurrent.Executor` that can be used to post tasks into the event loop thread in `graal-nodejs`. It is available as `require('node:graal').eventLoopExecutor`. ## Version 24.1.0 * ECMAScript 2024 mode/features enabled by default. From 422ee4d3c4b823cc810d66e2be8dfaac2a97dad6 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Wed, 11 Sep 2024 17:07:33 +0200 Subject: [PATCH 234/265] Allow to pass WebAssembly.Memory to a Worker. --- .../wasm/JSWebAssemblyMemoryObject.java | 6 +++- .../serialization/Deserializer.java | 29 +++++++++++++++++-- .../serialization/SerializationTag.java | 3 +- .../trufflenode/serialization/Serializer.java | 27 +++++++++++++---- 4 files changed, 55 insertions(+), 10 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyMemoryObject.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyMemoryObject.java index f8ccbf09122..15aad069e69 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyMemoryObject.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyMemoryObject.java @@ -58,7 +58,7 @@ public final class JSWebAssemblyMemoryObject extends JSNonProxyObject { private final Object wasmMemory; private JSArrayBufferObject bufferObject; - private boolean shared; + private final boolean shared; protected JSWebAssemblyMemoryObject(Shape shape, JSDynamicObject proto, Object wasmMemory, boolean shared) { super(shape, proto); @@ -70,6 +70,10 @@ public Object getWASMMemory() { return wasmMemory; } + public boolean isShared() { + return shared; + } + public JSArrayBufferObject getBufferObject(JSContext context, JSRealm realm) { if (bufferObject == null) { if (!shared) { diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/Deserializer.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/Deserializer.java index df571349a2f..f66256275b0 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/Deserializer.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/Deserializer.java @@ -52,6 +52,7 @@ import com.oracle.truffle.js.runtime.BigInt; import com.oracle.truffle.js.runtime.Errors; import com.oracle.truffle.js.runtime.GraalJSException; +import com.oracle.truffle.js.runtime.JSAgentWaiterList; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSErrorType; import com.oracle.truffle.js.runtime.JSException; @@ -75,6 +76,8 @@ import com.oracle.truffle.js.runtime.builtins.JSSet; import com.oracle.truffle.js.runtime.builtins.JSSharedArrayBuffer; import com.oracle.truffle.js.runtime.builtins.JSString; +import com.oracle.truffle.js.runtime.builtins.wasm.JSWebAssemblyMemory; +import com.oracle.truffle.js.runtime.builtins.wasm.JSWebAssemblyMemoryObject; import com.oracle.truffle.js.runtime.builtins.wasm.JSWebAssemblyModule; import com.oracle.truffle.js.runtime.objects.JSDynamicObject; import com.oracle.truffle.js.runtime.objects.JSObject; @@ -194,8 +197,11 @@ private Object readValue(JSRealm realm, SerializationTag tag) { return readJSError(realm); case WASM_MODULE_TRANSFER: return readWasmModuleTransfer(); + case WASM_MEMORY_TRANSFER: + return readWasmMemoryTransfer(realm); case SHARED_JAVA_OBJECT: - return readSharedJavaObject(realm); + Object hostValue = readSharedJavaObject(); + return realm.getEnv().asGuestValue(hostValue); default: throw Errors.createError("Deserialization of a value tagged " + tag); } @@ -558,14 +564,31 @@ public Object readWasmModuleTransfer() { return assignId(wasmModule); } - public Object readSharedJavaObject(JSRealm realm) { + public Object readWasmMemoryTransfer(JSRealm realm) { + SerializationTag sharedJavaObjectTag = readTag(); + assert sharedJavaObjectTag == SerializationTag.SHARED_JAVA_OBJECT; + Object wasmMemory = readSharedJavaObject(); + + sharedJavaObjectTag = readTag(); + assert sharedJavaObjectTag == SerializationTag.SHARED_JAVA_OBJECT; + JSAgentWaiterList waiterList = (JSAgentWaiterList) readSharedJavaObject(); + + JSContext context = realm.getContext(); + JSWebAssemblyMemoryObject webAssemblyMemory = JSWebAssemblyMemory.create(context, realm, wasmMemory, true); + JSArrayBufferObject arrayBuffer = webAssemblyMemory.getBufferObject(context, realm); + JSSharedArrayBuffer.setWaiterList(arrayBuffer, waiterList); + + return assignId(webAssemblyMemory); + } + + public Object readSharedJavaObject() { long messagePortPointer = readVarLong(); if (messagePortCache == null || messagePortCache.getMessagePortDataPointer() != messagePortPointer) { messagePortCache = SharedMemMessagingManager.getMessagePortDataFor(messagePortPointer); } Object element = messagePortCache.removeJavaRef(); assert element != null; - return realm.getEnv().asGuestValue(element); + return element; } public int readBytes(int length) { diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/SerializationTag.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/SerializationTag.java index 48daf477b4e..6c28e20f7d2 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/SerializationTag.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/SerializationTag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -68,6 +68,7 @@ public enum SerializationTag { ARRAY_BUFFER_TRANSFER('t'), // kArrayBufferTransfer ARRAY_BUFFER_VIEW('V'), // kArrayBufferView WASM_MODULE_TRANSFER('w'), // kWasmModuleTransfer + WASM_MEMORY_TRANSFER('m'), // kWasmMemoryTransfer BEGIN_JS_MAP(';'), // kBeginJSMap END_JS_MAP(':'), // kEndJSMap BEGIN_JS_SET('\''), // kBeginJSSet diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/Serializer.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/Serializer.java index 52af2018555..d8c9900ceac 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/Serializer.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/serialization/Serializer.java @@ -51,8 +51,11 @@ import com.oracle.truffle.api.TruffleLanguage.Env; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.runtime.BigInt; +import com.oracle.truffle.js.runtime.JSAgentWaiterList; +import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSErrorType; import com.oracle.truffle.js.runtime.JSException; +import com.oracle.truffle.js.runtime.JSRealm; import com.oracle.truffle.js.runtime.JSRuntime; import com.oracle.truffle.js.runtime.Strings; import com.oracle.truffle.js.runtime.Symbol; @@ -202,10 +205,10 @@ public void writeValue(Object value) { } else if (value instanceof Symbol) { NativeAccess.throwDataCloneError(delegate, Strings.concat(JSRuntime.safeToString(value), COULD_NOT_BE_CLONED)); } else if (env.isHostObject(value) && access.getCurrentMessagePortData() != null) { - writeSharedJavaObject(value); + writeSharedJavaObject(env.asHostObject(value)); } else if (value instanceof Long) { if (access.getCurrentMessagePortData() != null) { - writeSharedJavaObject(env.asBoxedGuestValue(value)); + writeSharedJavaObject(value); } else { writeIntOrDouble(((Long) value).doubleValue()); } @@ -417,8 +420,22 @@ private void writeJSWebAssemblyModule(JSWebAssemblyModuleObject wasmModule) { } private void writeJSWebAssemblyMemory(JSWebAssemblyMemoryObject wasmMemory) { - // non-shared WebAssembly.Memory cannot be cloned - NativeAccess.throwDataCloneError(delegate, Strings.concat(JSRuntime.safeToString(wasmMemory), COULD_NOT_BE_CLONED)); + if (wasmMemory.isShared()) { + writeTag(SerializationTag.WASM_MEMORY_TRANSFER); + + // Write wasm memory + writeSharedJavaObject(wasmMemory.getWASMMemory()); + + // Write waiter list of the underlying SharedArrayBuffer + JSRealm realm = JSRealm.get(null); + JSContext context = realm.getContext(); + JSArrayBufferObject arrayBuffer = wasmMemory.getBufferObject(context, realm); + JSAgentWaiterList waiterList = JSArrayBufferObject.getWaiterList(arrayBuffer); + writeSharedJavaObject(waiterList); + } else { + // non-shared WebAssembly.Memory cannot be cloned + NativeAccess.throwDataCloneError(delegate, Strings.concat(JSRuntime.safeToString(wasmMemory), COULD_NOT_BE_CLONED)); + } } private void writeJSObject(JSDynamicObject object) { @@ -624,7 +641,7 @@ private void writeSharedJavaObject(Object value) { writeTag(SerializationTag.SHARED_JAVA_OBJECT); writeVarInt(messagePort.getMessagePortDataPointer()); assignId(value); - messagePort.enqueueJavaRef(env.asHostObject(value)); + messagePort.enqueueJavaRef(value); } private void writeHostObject(Object object) { From b555984ab1945befe49a1480289b102269888ae5 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Wed, 11 Sep 2024 17:46:36 +0200 Subject: [PATCH 235/265] JSWebAssemblyMemoryObject for WasmMemory is agent-specific. --- .../js/builtins/ConstructorBuiltins.java | 5 +- .../builtins/wasm/JSWebAssemblyMemory.java | 49 +++++++++++++++++-- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java index 3c46d04d97a..e3072212df5 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java @@ -3269,7 +3269,8 @@ public ConstructWebAssemblyMemoryNode(JSContext context, JSBuiltin builtin, bool } @Specialization - protected JSObject constructMemory(JSDynamicObject newTarget, Object descriptor) { + protected JSObject constructMemory(JSDynamicObject newTarget, Object descriptor, + @Cached InlinedConditionProfile isShared) { if (!isObjectNode.executeBoolean(descriptor)) { throw Errors.createTypeError("WebAssembly.Memory(): Argument 0 must be a memory descriptor", this); } @@ -3282,7 +3283,7 @@ protected JSObject constructMemory(JSDynamicObject newTarget, Object descriptor) throw Errors.createRangeErrorFormat("WebAssembly.Memory(): Property 'initial': value %d is above the upper bound %d", this, initialInt, JSWebAssemblyMemory.MAX_MEMORY_SIZE); } Boolean shared = getSharedNode.executeValue(descriptor); - boolean sharedBoolean = Boolean.TRUE.equals(shared); + boolean sharedBoolean = isShared.profile(this, Boolean.TRUE.equals(shared)); int maximumInt; Object maximum = getMaximumNode.getValue(descriptor); if (maximum == Undefined.instance) { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyMemory.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyMemory.java index 35da4bc48f0..2b16133704d 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyMemory.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/wasm/JSWebAssemblyMemory.java @@ -40,9 +40,14 @@ */ package com.oracle.truffle.js.runtime.builtins.wasm; +import org.graalvm.collections.EconomicMap; + import com.oracle.truffle.api.object.Shape; +import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.builtins.wasm.WebAssemblyMemoryPrototypeBuiltins; +import com.oracle.truffle.js.runtime.Boundaries; +import com.oracle.truffle.js.runtime.JSAgent; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRealm; import com.oracle.truffle.js.runtime.Strings; @@ -103,14 +108,50 @@ public static JSWebAssemblyMemoryObject create(JSContext context, JSRealm realm, } public static JSWebAssemblyMemoryObject create(JSContext context, JSRealm realm, JSDynamicObject proto, Object wasmMemory, boolean shared) { - Object embedderData = JSWebAssembly.getEmbedderData(realm, wasmMemory); - if (embedderData instanceof JSWebAssemblyMemoryObject) { - return (JSWebAssemblyMemoryObject) embedderData; + if (shared) { + return createShared(context, realm, proto, wasmMemory); + } else { + Object embedderData = JSWebAssembly.getEmbedderData(realm, wasmMemory); + if (embedderData instanceof JSWebAssemblyMemoryObject webAssemblyMemory) { + return webAssemblyMemory; + } + JSWebAssemblyMemoryObject webAssemblyMemory = createImpl(context, realm, proto, wasmMemory, false); + JSWebAssembly.setEmbedderData(realm, wasmMemory, webAssemblyMemory); + return webAssemblyMemory; } + } + + private static JSWebAssemblyMemoryObject createShared(JSContext context, JSRealm realm, JSDynamicObject proto, Object wasmMemory) { + synchronized (wasmMemory) { + Object embedderData = JSWebAssembly.getEmbedderData(realm, wasmMemory); + EconomicMapHolder mapHolder; + if (embedderData instanceof EconomicMapHolder) { + mapHolder = (EconomicMapHolder) embedderData; + JSWebAssemblyMemoryObject webAssemblyMemory = Boundaries.economicMapGet(mapHolder.map, realm.getAgent()); + if (webAssemblyMemory != null) { + return webAssemblyMemory; + } + } else { + mapHolder = new EconomicMapHolder(); + JSWebAssembly.setEmbedderData(realm, wasmMemory, mapHolder); + } + JSWebAssemblyMemoryObject webAssemblyMemory = createImpl(context, realm, proto, wasmMemory, true); + Boundaries.economicMapPut(mapHolder.map, realm.getAgent(), webAssemblyMemory); + return webAssemblyMemory; + } + } + + private static JSWebAssemblyMemoryObject createImpl(JSContext context, JSRealm realm, JSDynamicObject proto, Object wasmMemory, boolean shared) { JSObjectFactory factory = context.getWebAssemblyMemoryFactory(); var shape = factory.getShape(realm, proto); var object = factory.initProto(new JSWebAssemblyMemoryObject(shape, proto, wasmMemory, shared), realm, proto); - JSWebAssembly.setEmbedderData(realm, wasmMemory, object); return factory.trackAllocation(object); } + + // EconomicMap is not an interop value => we cannot pass it to WasmMemory + // => we need to wrap it in TruffleObject + static class EconomicMapHolder implements TruffleObject { + final EconomicMap map = Boundaries.economicMapCreate(); + } + } From cd90690ab3b20d995c28edf970ebe53ac22d15c4 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Wed, 11 Sep 2024 17:53:06 +0200 Subject: [PATCH 236/265] Testing the passing of WebAssembly.Memory to a Worker. --- graal-nodejs/test/graal/unit/wasm_memory.js | 39 +++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/graal-nodejs/test/graal/unit/wasm_memory.js b/graal-nodejs/test/graal/unit/wasm_memory.js index d443646cb9a..0b2d8ac26f4 100644 --- a/graal-nodejs/test/graal/unit/wasm_memory.js +++ b/graal-nodejs/test/graal/unit/wasm_memory.js @@ -122,6 +122,45 @@ if (typeof WebAssembly !== 'undefined') { let memory = new WebAssembly.Memory({ initial: 1 }); assert.strictEqual(module.WasmMemory_Buffer(memory), memory.buffer); }); + + it('can be sent to a Worker', function(done) { + const { Worker } = require('worker_threads'); + + const memory = new WebAssembly.Memory({initial: 1, maximum: 1, shared: true}); + + const w = new Worker(` + const { parentPort } = require('worker_threads'); + + let memory; + + const notify = function() { + const result = Atomics.notify(new Int32Array(memory.buffer), 0); + if (result === 1) { + parentPort.postMessage('done'); + } else { + // There is a tiny chance that the waiting in the other + // thread haven't started yet => try again later + setTimeout(notify, 100); + } + }; + + parentPort.on('message', (message) => { + memory = message; + notify(); + });`, + { + eval: true + }); + + w.on('message', (message) => { + assert.strictEqual(message, 'done'); + w.terminate().then(() => done()); + }); + + w.postMessage(memory); + + assert.strictEqual(Atomics.wait(new Int32Array(memory.buffer), 0, 0), 'ok'); + }); }); }); } From f67a95f3a3dac073ec5e5878544aae17e5e9d3bb Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Wed, 11 Sep 2024 18:55:23 +0200 Subject: [PATCH 237/265] Running more WebAssembly-related graal-node.js tests. --- graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py b/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py index 963f6922e4e..9c4ac1e8ef8 100644 --- a/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py +++ b/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py @@ -84,10 +84,15 @@ def _graal_nodejs_post_gate_runner(args, tasks): join('es-module', 'test-wasm-memory-out-of-bound.js'), join('es-module', 'test-wasm-simple.js'), join('es-module', 'test-wasm-web-api.js'), + join('parallel', 'test-blob.js'), join('parallel', 'test-fetch.mjs'), join('parallel', 'test-fetch-disabled.mjs'), + join('parallel', 'test-fetch-mock.js'), + join('parallel', 'test-http-response-setheaders.js'), + join('parallel', 'test-websocket.js'), join('parallel', 'test-whatwg-webstreams-transfer.js'), - join('parallel', 'test-worker-message-port-wasm-module.js') + join('parallel', 'test-worker-message-port-wasm-module.js'), + join('parallel', 'test-worker-message-port-wasm-threads.js') ] for test in wasm_tests: node(commonArgs + [join(_suite.dir, 'test', test)]) From 8497e148c3b1168fea3c1bfc7bf4ac1ee767aba4 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Wed, 11 Sep 2024 18:56:09 +0200 Subject: [PATCH 238/265] WebAssembly is enabled by default (when available) in (tests of) graal-node.js. --- graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py | 1 - graal-nodejs/test/graal/package.json | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py b/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py index 9c4ac1e8ef8..e27aa4bee90 100644 --- a/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py +++ b/graal-nodejs/mx.graal-nodejs/mx_graal_nodejs.py @@ -71,7 +71,6 @@ def _graal_nodejs_post_gate_runner(args, tasks): npm(['--scripts-prepend-node-path=auto', 'install', '--nodedir=' + _suite.dir] + commonArgs, cwd=unitTestDir) npm(['--scripts-prepend-node-path=auto', 'test'] + commonArgs + testArgs, cwd=unitTestDir) if mx.suite('wasm', fatalIfMissing=False): - npm(['--scripts-prepend-node-path=auto', 'run', 'testwasm'] + commonArgs + testArgs, cwd=unitTestDir) node(commonArgs + ['-e', 'console.log(WebAssembly)']) # check that fetch API is available when WebAssembly is available node(commonArgs + ['-e', 'FormData']) diff --git a/graal-nodejs/test/graal/package.json b/graal-nodejs/test/graal/package.json index 1132949bfe8..7372749cf8e 100644 --- a/graal-nodejs/test/graal/package.json +++ b/graal-nodejs/test/graal/package.json @@ -9,7 +9,6 @@ }, "scripts": { "install": "node-gyp rebuild", - "test": "node --expose-gc index.js", - "testwasm": "node --experimental-options --js.webassembly=true --expose-gc index.js" + "test": "node --expose-gc index.js" } } From 56a1ea765dff214898eeaa6302ebdb1367f49fd0 Mon Sep 17 00:00:00 2001 From: Jan Stola Date: Wed, 11 Sep 2024 20:49:15 +0200 Subject: [PATCH 239/265] Replacing equality (==) by identity (===) in graal-node.js unit tests. --- graal-nodejs/test/graal/unit/javaMessages.js | 2 +- graal-nodejs/test/graal/unit/wasm_memory.js | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/graal-nodejs/test/graal/unit/javaMessages.js b/graal-nodejs/test/graal/unit/javaMessages.js index 33d25e234de..b39258609c1 100644 --- a/graal-nodejs/test/graal/unit/javaMessages.js +++ b/graal-nodejs/test/graal/unit/javaMessages.js @@ -165,7 +165,7 @@ describe('Java interop messages', function() { eval: true }); w.on('message', (m) => { - if (++received == workersNum) { + if (++received === workersNum) { assert(map.size() === workersNum); for (var i = 0; i < workersNum; i++) { assert(map.get(42 + i) === true); diff --git a/graal-nodejs/test/graal/unit/wasm_memory.js b/graal-nodejs/test/graal/unit/wasm_memory.js index 0b2d8ac26f4..0685ff215a0 100644 --- a/graal-nodejs/test/graal/unit/wasm_memory.js +++ b/graal-nodejs/test/graal/unit/wasm_memory.js @@ -73,7 +73,7 @@ if (typeof WebAssembly !== 'undefined') { let calls = 0; assert.ok(module.WasmMemory_CheckBackingStore(memory.buffer, (len, elem) => { - if (calls == 0) { + if (calls === 0) { assert.strictEqual(len, 4 * PAGE_SIZE); assert.strictEqual(elem, 42); @@ -86,10 +86,10 @@ if (typeof WebAssembly !== 'undefined') { array = new Uint8Array(memory.buffer); assert.strictEqual(array[0], 42); array[0] = 44; - } else if (calls == 1) { + } else if (calls === 1) { // still using old backing store // V8 may grow the wasm memory in place, so we allow that as well - if (len == 4 * PAGE_SIZE) { + if (len === 4 * PAGE_SIZE) { // grow with copy assert.strictEqual(len, 4 * PAGE_SIZE); assert.strictEqual(elem, 42); @@ -98,7 +98,7 @@ if (typeof WebAssembly !== 'undefined') { assert.strictEqual(len, 5 * PAGE_SIZE); assert.strictEqual(elem, 44); } - } else if (calls == 2) { + } else if (calls === 2) { // GetBackingStore() of detached buffer assert.strictEqual(len, 0); assert.strictEqual(elem, undefined); @@ -108,7 +108,7 @@ if (typeof WebAssembly !== 'undefined') { assert.strictEqual(calls, 3); assert.ok(module.WasmMemory_CheckBackingStore(memory.buffer, (len, elem) => { - if (calls == 3) { + if (calls === 3) { // new, grown backing store assert.strictEqual(len, 5 * PAGE_SIZE); assert.strictEqual(elem, 44); From 7505125b1fd54d8f416da1212ba4d8f9e9c6b3ce Mon Sep 17 00:00:00 2001 From: Olya Gupalo Date: Mon, 22 Jul 2024 13:45:14 +0300 Subject: [PATCH 240/265] Review and update GraalJS user documentation and project's README --- CHANGELOG.md | 2 +- README.md | 155 +++++++------- docs/user/FAQ.md | 150 +++++-------- docs/user/JavaInteroperability.md | 178 ++++++++------- docs/user/JavaScriptCompatibility.md | 105 +++++---- docs/user/Modules.md | 77 ++++--- docs/user/Multithreading.md | 23 +- docs/user/NashornMigrationGuide.md | 190 +++++++++-------- docs/user/NodeJS.md | 185 +++++++++++++--- docs/user/NodeJSVSJavaScriptContext.md | 47 ++-- docs/user/OperatorOverloading.md | 60 +++--- docs/user/Options.md | 104 ++++----- docs/user/README.md | 285 +++++++++++++------------ docs/user/RhinoMigrationGuide.md | 37 ++-- docs/user/RunOnJDK.md | 48 +++-- docs/user/ScriptEngine.md | 65 +++--- graal-js/README.md | 71 +++--- 17 files changed, 958 insertions(+), 824 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ce227a3169..b970a4bbea5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# GraalVM JavaScript (Graal.js) Changelog +# GraalJS Changelog This changelog summarizes major changes between GraalVM versions of the GraalVM JavaScript (ECMAScript) language runtime. The main focus is on user-observable behavior of the engine. diff --git a/README.md b/README.md index 248d6c0c48a..a10fd5ba081 100644 --- a/README.md +++ b/README.md @@ -1,119 +1,120 @@ [![https://graalvm.slack.com](https://img.shields.io/badge/slack-join%20channel-active)](https://www.graalvm.org/slack-invitation/) -A high performance implementation of the JavaScript programming language. -Built on the GraalVM by Oracle Labs. +# GraalJS -The goals of GraalVM JavaScript are: +GraalJS is a JavaScript engine implemented in Java on top of GraalVM. +It is an ECMAScript-compliant runtime to execute JavaScript and Node.js applications, and includes all the benefits from the GraalVM stack including interoperability with Java. +GraalJS is an open-source project. -* Execute JavaScript code with best possible performance +The goals of GraalJS are: * [Full compatibility with the latest ECMAScript specification](docs/user/JavaScriptCompatibility.md) -* Support Node.js applications, including native packages ([check](https://www.graalvm.org/compatibility/)) -* Allow simple upgrading from [Nashorn](docs/user/NashornMigrationGuide.md) or [Rhino](docs/user/RhinoMigrationGuide.md) based applications -* [Fast interoperability](https://www.graalvm.org/reference-manual/polyglot-programming/) with Java, Scala, or Kotlin, or with other GraalVM languages like Ruby, Python, or R -* Be embeddable in systems like [Oracle RDBMS](https://labs.oracle.com/pls/apex/f?p=LABS:project_details:0:15) or MySQL - +* [Interoperability with Java](docs/user/JavaInteroperability.md) +* Interoperability with WebAssembly using the JavaScript WebAssembly API +* Running JavaScript with the best possible performance +* Support for Node.js applications, including native packages +* Simple upgrading from applications based on [Nashorn](docs/user/NashornMigrationGuide.md) or [Rhino](docs/user/RhinoMigrationGuide.md) +* Embeddability in systems like [Oracle RDBMS](https://labs.oracle.com/pls/apex/f?p=LABS:project_details:0:15) or MySQL ## Getting Started -The preferred way to run GraalVM JavaScript (a.k.a. GraalJS) is from a [GraalVM](https://www.graalvm.org/downloads/). -As of GraalVM for JDK 21, (23.1), GraalVM JavaScript and Node.js runtimes are available as [standalone distributions](https://github.com/oracle/graaljs/releases) and [Maven artifacts](https://central.sonatype.com/artifact/org.graalvm.polyglot/js) (but no longer as GraalVM components). -See the documentation on the [GraalVM website](https://www.graalvm.org/latest/reference-manual/js/) for more information on how to set up GraalVM JavaScript. -### Standalone Distribution -To install GraalVM JavaScript using the [standalone distribution], simply download and extract the desired archive from the [GitHub Releases](https://github.com/oracle/graaljs/releases) page. -The standalone archives for the JavaScript and Node.js distributions are named `graaljs[-community][-jvm]---.tar.gz` and `graalnodejs[-community][-jvm]---.tar.gz`, respectively. -Four different available configurations are available for each component and platform combination: +As of version 23.1.0, GraalJS is available as [Maven artifacts](https://central.sonatype.com/artifact/org.graalvm.polyglot/js). +We also provide [standalone distributions](https://github.com/oracle/graaljs/releases) of the JavaScript and Node.js runtimes. -| Runtime | License | Archive Infix | -| -------------| ------- | ---------------- | -| Native | GFTC | _none_ | -| JVM | GFTC | `-jvm` | -| Native | UPL | `-community` | -| JVM | UPL | `-community-jvm` | +### Maven Artifacts -After installation, the `js` or `node` executable in the `bin` subdirectory can be used to run JavaScript files or Node modules, respectively. -If no file is provided on the command line, an interactive shell (REPL) will be spawned. +Thanks to GraalJS, you can easily embed JavaScript into a Java application. +All necessary artifacts can be downloaded directly from Maven Central. -### Maven Artifact -All required artifacts for embedding GraalVM JavaScript can be found in the Maven dependency group [`org.graalvm.polyglot`](https://central.sonatype.com/namespace/org.graalvm.polyglot). +All artifacts relevant to embedders can be found in the Maven dependency group [org.graalvm.polyglot](https://central.sonatype.com/namespace/org.graalvm.polyglot). -Here is a minimal Maven dependency setup that you can copy into your `pom.xml`: +Below is a minimal Maven dependency setup that you can copy into your _pom.xml_: ```xml - org.graalvm.polyglot - polyglot - 23.1.0 + org.graalvm.polyglot + polyglot + ${graaljs.version} - org.graalvm.polyglot - js - 23.1.0 - pom + org.graalvm.polyglot + js + ${graaljs.version} + pom - ``` +This enables GraalJS which is built on top of Oracle GraalVM and licensed under the [GraalVM Free Terms and Conditions (GFTC)](https://www.oracle.com/downloads/licenses/graal-free-license.html). +Use `js-community` if you want to use GraalJS built on GraalVM Community Edition. -See the [polyglot embedding demonstration](https://github.com/graalvm/polyglot-embedding-demo) on GitHub for a complete runnable example. -Language and tool dependencies use the [GraalVM Free Terms and Conditions (GFTC)](https://www.oracle.com/downloads/licenses/graal-free-license.html) license by default. -To use community-licensed versions instead, add the `-community` suffix to each language and tool dependency, e.g.: -```xml - - org.graalvm.polyglot - js-community - 23.1.0 - pom - -``` -To access [polyglot isolate](https://www.graalvm.org/latest/reference-manual/embed-languages/#polyglot-isolates) artifacts (GFTC only), use the `-isolate` suffix instead (e.g. `js-isolate`). +To access [polyglot isolate](https://www.graalvm.org/reference-manual/embed-languages/#polyglot-isolates) artifacts (GFTC only), use the `-isolate` suffix instead (e.g. `js-isolate`). + +See the [polyglot embedding demonstration](https://github.com/graalvm/polyglot-embedding-demo) on GitHub for a complete runnable example. -If you prefer running it on a stock JVM, please have a look at the documentation in [`RunOnJDK.md`](https://github.com/graalvm/graaljs/blob/master/docs/user/RunOnJDK.md). +You can use GraalJS with GraalVM JDK, Oracle JDK, or OpenJDK. +If you prefer running on a stock JVM, have a look at [Run GraalJS on a Stock JDK](docs/user/RunOnJDK.md). Note that in this mode many features and optimizations of GraalVM are not available. Due to those limitations, running on a stock JVM is not a supported feature - please use a GraalVM instead. -## Documentation +### Standalone Distributions + +Standalone distributions are published on [GitHub](https://github.com/oracle/graaljs/releases). +There are two language runtime options to choose from: +- Native launcher compiled ahead of time with GraalVM Native Image; +- JVM-based runtime. + +To distinguish between them, a standalone that comes with a JVM has a `-jvm` infix in the name. +Also, the GraalVM Community Edition version has `-community` in the name, for example, `graaljs-community---.tar.gz`. -Extensive documentation is available on [graalvm.org](https://www.graalvm.org/): see [Getting Started](https://www.graalvm.org/docs/getting-started/) and the more extensive [JavaScript and Node.js Reference Manual](https://www.graalvm.org/reference-manual/js/). -In addition, there is documentation in the source code repository in the [`docs`](https://github.com/graalvm/graaljs/tree/master/docs) directory, for [users](https://github.com/graalvm/graaljs/tree/master/docs/user) and [contributors](https://github.com/graalvm/graaljs/tree/master/docs/contributor). +Four different configurations are available for each component and platform combination: -For contributors, a guide how to build GraalVM JavaScript from source code can be found in [`Building.md`](https://github.com/graalvm/graaljs/tree/master/docs/Building.md). +| Runtime | License | Archive Infix | +| -------------| ------- | ---------------- | +| Native | GFTC | _none_ | +| JVM | GFTC | `-jvm` | +| Native | UPL | `-community` | +| JVM | UPL | `-community-jvm` | -## Current Status +To install GraalJS from a standalone, download and extract the archive from the [GitHub Releases](https://github.com/oracle/graaljs/releases) page. +After the installation, the `js` or `node` executable in the `bin` subdirectory can be used to run JavaScript files or Node modules, respectively. +If no file is provided on the command line, an interactive shell (REPL) will be spawned. -GraalVM JavaScript is compatible with the [ECMAScript 2023 specification](https://262.ecma-international.org/14.0/). -New features, e.g. `ECMAScript proposals` scheduled to land in future editions, are added frequently and are accessible behind a flag. -See the [CHANGELOG.md](https://github.com/graalvm/graaljs/tree/master/CHANGELOG.md) for the proposals already adopted. +## Node.js Runtime -In addition, some popular extensions of other engines are supported, see [`JavaScriptCompatibility.md`](https://github.com/graalvm/graaljs/tree/master/docs/user/JavaScriptCompatibility.md). +GraalJS can run unmodified Node.js applications. +GraalVM's Node.js runtime is based on a recent version of Node.js, and runs the GraalJS engine instead of Google V8. +It provides high compatibility with the existing NPM packages. +This includes NPM packages with native implementations. +Note that some NPM modules may require to be recompiled from source with GraalJS (if they ship with binaries that have been compiled for Node.js based on V8). -### Node.js support +Node.js is available as a separate [standalone distribution](#standalone-distributions). +See [how to get started with Node.js](NodeJS.md). -GraalVM JavaScript can execute Node.js applications. -It provides high compatibility with existing npm packages, with high likelihood that your application will run out of the box. -This includes npm packages with native implementations. -Note that some npm modules will require to be re-compiled from source with GraalVM JavaScript if they ship with binaries that have been compiled for Node.js based on V8. -Node.js is a separate [standalone distribution](#standalone-distribution). +## Documentation -### Compatibility on Operating Systems +Extensive user documentation is available on the [website](https://www.graalvm.org/reference-manual/js/). +In addition, there is documentation in this repository under [docs](https://github.com/oracle/graaljs/tree/master/docs), for [users](https://github.com/oracle/graaljs/tree/master/docs/user) and [contributors](https://github.com/oracle/graaljs/tree/master/docs/contributor). +For contributing, see also a [guide on how to build GraalJS from source code](docs/Building.md). -The core JavaScript engine is a Java application and is thus in principle compatible with every operating system that provides a compatible JVM, [see `RunOnJDK.md`](https://github.com/graalvm/graaljs/tree/master/docs/user/RunOnJDK.md). -We provide binary distributions and fully support GraalVM JavaScript on Linux (AMD64, AArch64), MacOS (AMD64, AArch64), and Windows (AMD64), currently. +## Compatibility -## GraalVM JavaScript Reference Manual +GraalJS is compatible with the [ECMAScript 2024 specification](https://262.ecma-international.org/). +New features, new ECMAScript proposals, scheduled to land in future editions, are added frequently and are accessible behind an option. +See the [CHANGELOG.md](CHANGELOG.md) for the proposals already adopted. -A reference manual for GraalVM JavaScript is available on the [GraalVM website](https://www.graalvm.org/reference-manual/js/). +In addition, some popular extensions of other engines are supported. See [GraalJS Compatibility](docs/user/JavaScriptCompatibility.md). -## Stay connected with the community +## Operating Systems Compatibility -See [graalvm.org/community](https://www.graalvm.org/community/) on how to stay connected with the development community. -The channel _graaljs_ on [graalvm.slack.com](https://www.graalvm.org/slack-invitation) is a good way to get in touch with us. -Please report JavaScript-specific issues on the [`oracle/graaljs`](https://github.com/oracle/graaljs/) GitHub repository. +The core JavaScript engine is a Java application and is thus compatible with every operating system that provides a compatible JVM. See [Run GraalJS on a Stock JDK](docs/user/RunOnJDK.md). +We provide binary distributions and fully support GraalJS on Linux (x64, AArch64), macOS (x64, AArch64), and Windows (x64), currently. -## License +## Stay Connected with the Community -GraalVM JavaScript source code and community distributions are available under the following license: +See [graalvm.org/community](https://www.graalvm.org/community/) for how to stay connected with the development community. +The channel _graaljs_ on [graalvm.slack.com](https://www.graalvm.org/slack-invitation) is a good way to get in touch with the team behind GraalJS. +Report any GraalJS-specific issues at the [oracle/graaljs](https://github.com/oracle/graaljs/) GitHub repository. -* [The Universal Permissive License (UPL), Version 1.0](https://opensource.org/licenses/UPL) +## License -Non-community artifacts are provided under the following license: +GraalJS source code and community distributions are available under the [Universal Permissive License (UPL), Version 1.0](https://opensource.org/licenses/UPL). -* [GraalVM Free Terms and Conditions (GFTC) including License for Early Adopter Versions](https://www.oracle.com/downloads/licenses/graal-free-license.html) +Non-community artifacts are provided under the [GraalVM Free Terms and Conditions (GFTC) including License for Early Adopter Versions](https://www.oracle.com/downloads/licenses/graal-free-license.html). diff --git a/docs/user/FAQ.md b/docs/user/FAQ.md index 360ceb726bf..c44d2de5a71 100644 --- a/docs/user/FAQ.md +++ b/docs/user/FAQ.md @@ -4,138 +4,98 @@ toc_group: js link_title: FAQ permalink: /reference-manual/js/FAQ/ --- + # Frequently Asked Questions Below are the most frequently asked questions and answers about JavaScript running on GraalVM. ## Compatibility -### Is GraalVM compatible with the JavaScript language? -GraalVM is compatible with the ECMAScript 2023 specification and is further developed alongside the 2024 draft specification. -The compatibility of GraalVM's JavaScript runtime is verified by external sources, like the [Kangax ECMAScript compatibility table](https://kangax.github.io/compat-table/es6/). - -GraalVM JavaScript is tested against a set of test engines, like the official test suite of ECMAScript, [test262](https://github.com/tc39/test262), as well as tests published by V8 and Nashorn, Node.js unit tests, and GraalVM's own unit tests. - -For a reference of the JavaScript APIs that GraalVM supports, see [GRAAL.JS-API](https://github.com/graalvm/graaljs/blob/master/docs/user/JavaScriptCompatibility.md). - -### Is GraalVM compatible with the original node implementation? -Node.js based on GraalVM is largely compatible with the original Node.js (based on the V8 engine). -This leads to a high number of npm-based modules being compatible with GraalVM. -In fact, out of the 100k npm modules we test, more than 94% of them pass all tests. -Still, several sources of differences have to be considered: - -- **Setup:** -GraalVM mostly mimicks the original setup of Node, including the `node` executable, `npm`, and similar. -However, not all command-line options are supported (or behave exactly identically). -Modules might require that native modules are (re-)compiled against the v8.h file. - -Since GraalVM 21.1, Node.js and all related executables (e.g., `node`, `npm`, etc.) are not included by default in the GraalVM binary. -Node.js support is now packaged in a separate component that can be installed with the _GraalVM Updater_ using `$JAVA_HOME/bin/gu install nodejs`. - -- **Internals:** -GraalVM is implemented on top of a JVM, and thus has a different internal architecture than Node.js based on V8. -This implies that some internal mechanisms behave differently and cannot exactly replicate V8 behaviour. -This will hardly ever affect user code, but might affect modules implemented natively, depending on V8 internals. - -- **Performance:** -Due to GraalVM being implemented on top of a JVM, performance characteristics vary from the original native implementation. -While GraalVM's peak performance can match V8 on many benchmarks, it will typically take longer to reach the peak (known as _warmup_). -Be sure to give the GraalVM compiler some extra time when measuring (peak) performance. +### Is GraalJS compatible with the JavaScript language? +GraalJS is compatible with the ECMAScript 2024 specification and is further developed alongside the 2025 draft specification. +The compatibility of GraalJS is verified by external sources, such as the [Kangax ECMAScript compatibility table](https://kangax.github.io/compat-table/es6/). -- **Compatiblity:** -GraalVM uses the following approaches to check and retain compatibility with Node.js code: +GraalJS is tested against a set of test engines, such as the official test suite of ECMAScript, [test262](https://github.com/tc39/test262), as well as tests published by V8 and Nashorn, Node.js unit tests, and GraalJS's own unit tests. -* node-compat-table: GraalVM is compared against other engines using the _node-compat-table_ module, highlighting incompatibilities that might break Node.js code. -* automated mass-testing of modules using _mocha_: in order to test a large set of modules, GraalVM is tested against 95k modules that use the mocha test framework. Using mocha allows automating the process of executing the test and comprehending the test result. -* manual testing of popular modules: a select list of npm modules is tested in a manual test setup. These highly-relevant modules are tested in a more sophisticated manner. +For reference documentation describing the JavaScript APIs that GraalVM supports, see [GRAAL.JS-API](https://github.com/graalvm/graaljs/blob/master/docs/user/JavaScriptCompatibility.md). -### My application used to run on Nashorn, it does not work on GraalVM JavaScript? +### My application used to run on Nashorn, why does it not work on GraalJS? Reason: -* GraalVM JavaScript tries to be compatible with the ECMAScript specification, as well as competing engines (including Nashorn). In some cases, this is a contradicting requirement; then, ECMAScript is given precedence. Also, there are cases where GraalVM Javascript is not exactly replicating Nashorn features intentionally, e.g., for security reasons. +* GraalJS tries to be compatible with the ECMAScript specification, as well as competing engines (including Nashorn). In some cases, this is a contradicting requirement; in these cases, ECMAScript is given precedence. Also, there are cases where GraalJS does not exactly replicate Nashorn features intentionally, for example, for security reasons. Solution: -* In many cases, enabling GraalVM's Nashorn compatibility mode enables features not enabled by default. Note that this can have negative effects on application security! See the [Nashorn Migration Guide](NashornMigrationGuide.md) for details. +* Enable GraalJS's Nashorn compatibility mode to add features not enabled by default—this should resolve most cases. However, note that this can have negative effects on application security! See the [Nashorn Migration Guide](NashornMigrationGuide.md) for details. Specific applications: * For JSR 223 ScriptEngine, you might want to set the system property `polyglot.js.nashorn-compat` to `true` in order to use the Nashorn compatibility mode. -* For `ant`, use `ANT_OPTS="-Dpolyglot.js.nashorn-compat=true" ant` when using GraalVM JavaScript via ScriptEngine. +* For `ant`, use the `ANT_OPTS` environment variable (`ANT_OPTS="-Dpolyglot.js.nashorn-compat=true"`) when using GraalJS via ScriptEngine. -### Builtin functions like `array.map()` or `fn.apply()` are not available on non-JavaScript objects like `ProxyArray`s from Java +### Why are built-in functions such as `array.map()` or `fn.apply()` not available on non-JavaScript objects such as `ProxyArray`s from Java? Reason: -* Java objects provided to JavaScript are treated as close as possible to their JavaScript counterpart. For instance, Java arrays provided to JavaScript are treated like JavaScript _Array exotic objects_ (JavaScript arrays) whenever possible; the same is true for _functions_. One obvious difference is that such object's prototype is `null`. This means that while you can, e.g., read the `length` or read and write the values of a Java array in JavaScript code, you cannot call `sort()` on it, as the `Array.prototype` is not provided by default. +* Java objects provided to JavaScript are treated as closely as possible to their JavaScript counterparts. For example, Java arrays provided to JavaScript are treated like JavaScript _Array exotic objects_ (JavaScript arrays) whenever possible; the same is true for _functions_. One obvious difference is that such object's prototype is `null`. This means that while you can, for example, read the `length` or read and write the values of a Java array in JavaScript code, you cannot call `sort()` on it, as the `Array.prototype` is not provided by default. Solution: -* While the objects do not have the methods of the prototype assigned, you can explicitly call them, e.g., `Array.prototype.call.sort(myArray)`. -* We offer the option `js.foreign-object-prototype`. When enabled, objects on the JavaScript side get the most prototype (e.g. `Array.prototype`, `Function.prototype`, `Object.prototype`) set and can thus behave more similarly to native JavaScript objects of the respective type. Normal JavaScript precedence rules apply here, e.g., own properties (of the Java object in that case) take precedence over and hide properties from the prototype. +* While the objects do not have the methods of the prototype assigned, you can explicitly call them, for example, `Array.prototype.call.sort(myArray)`. +* We offer the option `js.foreign-object-prototype`. When enabled, objects on the JavaScript side get the most applicable prototype set (such as `Array.prototype`, `Function.prototype`, `Object.prototype`) and can thus behave more similarly to native JavaScript objects of the respective type. Normal JavaScript precedence rules apply here, for example, an object's own properties (of the Java object in that case) take precedence over and hide properties from the prototype. -Note that while the JavaScript builtin functions. e.g., from `Array.prototype` can be called on the respective Java types, those functions expect JavaScript semantics. -This for instance means that operations might fail (typically with a `TypeError`: `Message not supported`) when an operation is not supported in Java. -Consider `Array.prototype.push` as an example: while arrays can grow in size in JavaScript, they are fixed-size in Java, thus pushing a value is semantically not possible and will fail. +Note that while the JavaScript built-in functions, for example, from `Array.prototype` can be called on the respective Java types, those functions expect JavaScript semantics. +This means that operations might fail (typically with a `TypeError`: `Message not supported`) when an operation is not supported in Java. +Consider `Array.prototype.push` as an example: arrays can grow in size in JavaScript, whereas they are fixed-size in Java, thus pushing a value is semantically not possible and will fail. In such cases, you can wrap the Java object and handle that case explicitly. Use the interfaces `ProxyObject` and `ProxyArray` for that purpose. -### How can one verify GraalVM works on their application? -If your module ships with tests, execute them with GraalVM. Of course, this will only test your application, but not its dependencies. -You can use the [Compatibility](https://www.graalvm.org/compatibility/) tool to find whether the module you are interested in is tested on GraalVM, and whether the tests pass successfully. -Additionally, you can upload your `package-lock.json` or `package.json` file into that tool and it will analyze all your dependencies at once. +### How can I verify GraalJS works on my application? + +If your module ships with tests, execute them with GraalJS. Of course, this will only test your application, not its dependencies. +You can use the [GraalVM Language Compatibility](https://www.graalvm.org/compatibility/) tool to discover if the module you are interested in is tested on GraalJS, and whether its tests pass successfully. +Additionally, you can upload your _package-lock.json_ or _package.json_ file into that tool and it will analyze all your dependencies. ## Performance -### My application is slower on GraalVM JavaScript than on another engine +### Why is my application slower on GraalJS than on another engine? Reason: -* Ensure your benchmark considers warmup. During the first few iterations, GraalVM JavaScript may be slower than other engines, but after sufficient warmup, this difference should level out. -* GraalVM JavaScript is shipped in two different standalones: Native (default) and JVM (with a `-jvm` infix). While the default _Native_ mode offers faster startup and lower latency, it might exhibit slower peak performance (lower throughput) once the application is warmed up. In the _JVM_ mode, the application might need hundreds of milliseconds more to start, but typically shows better peak performance. +* Ensure your benchmark considers warmup. During the first few iterations, GraalJS may be slower than other engines, but after sufficient warmup, this difference should level out. +* GraalJS is shipped in two different standalones: Native (default) and JVM (with a `-jvm` infix). The default _Native_ mode offers faster startup and lower latency, but it might exhibit slower peak performance (lower throughput) once the application is warmed up. In _JVM_ mode, your application might need hundreds of milliseconds more to start, but typically exhibits better peak performance. * Repeated execution of code via newly created `org.graalvm.polyglot.Context` is slow, despite the same code being executed every time. Solution: * Use proper warmup in your benchmark, and disregard the first few iterations where the application still warms up. -* When embedding GraalVM JavaScript in a Java application, ensure you're running on a GraalVM JDK for best performance. -* Use `-jvm` standalones for slower startup, but higher peak performance. -* Double-check you have no flags set that might lower your performance, e.g., `-ea`/`-esa`. -* When running code via `org.graalvm.polyglot.Context`, make sure that one `org.graalvm.polyglot.Engine` object is shared and passed to each newly created `Context`. Use `org.graalvm.polyglot.Source` objects and cache them when possible. Then, GraalVM makes sure already compiled code can be shared across the Contexts, leading to improved performance. See [Reference Manual: Code Caching across multiple Contexts](https://www.graalvm.org/latest/reference-manual/embed-languages/#code-caching-across-multiple-contexts) for more details and an example. -* Try to minify the problem to the root cause and [file an issue](https://github.com/graalvm/graaljs/issues) so the GraalVM team can have a look. +* When embedding GraalJS in a Java application, ensure you're running on a GraalVM JDK for best performance. +* Use a JVM standalone for slower startup, but higher peak performance. +* Double check you have no options set that might lower your performance, for example, `-ea`/`-esa`. +* When running code via `org.graalvm.polyglot.Context`, make sure that one `org.graalvm.polyglot.Engine` object is shared and passed to each newly created `Context`. Use `org.graalvm.polyglot.Source` objects and cache them when possible. Then, GraalVM shares existing compiled code across the Contexts, leading to improved performance. See [Code Caching Across Multiple Contexts](https://www.graalvm.org/latest/reference-manual/embed-languages/#code-caching-across-multiple-contexts) for more details and an example. +* Try to reduce the problem to its root cause and [file an issue](https://github.com/graalvm/graaljs/issues) so the GraalVM team can have a look. -### How to achieve the best peak performance? -Here are a few tips you can follow to analyse and improve peak performance: +### How can I achieve the best peak performance? +Here are a few tips you can follow to analyze and improve peak performance: -* When measuring, ensure you have given the GraalVM compiler enough time to compile all hot methods before starting to measure peak performance. A useful command line option for that is `--engine.TraceCompilation=true` -- this outputs a message whenever a (JavaScript) method is compiled. As long as this still prints frequently, measurement should not yet start. -* Compare the performance between Native Image and the JVM mode if possible. Depending on the characteristics of your application, one or the other might show better peak performance. +* When measuring, ensure you have given the Graal compiler enough time to compile all hot methods before starting to measure peak performance. A useful command line option for that is `--engine.TraceCompilation=true`—this outputs a message whenever a (JavaScript) method is compiled. Do not begin your measurement until this message becomes less frequent. +* Compare the performance between Native Image and JVM mode if possible. Depending on the characteristics of your application, one or the other might show better peak performance. * The Polyglot API comes with several tools and options to inspect the performance of your application: * `--cpusampler` and `--cputracer` will print a list of the hottest methods when the application is terminated. Use that list to figure out where most time is spent in your application. - * `--experimental-options --memtracer` can help you understand the memory allocations of your application. Refer to the [Profiling Command Line Tool](https://github.com/oracle/graal/blob/master/docs/tools/profiling.md) reference for more detail. + * `--experimental-options --memtracer` can help you understand the memory allocations of your application. Refer to [Profiling Command Line Tool](https://github.com/oracle/graal/blob/master/docs/tools/profiling.md) for more detail. -### What is the difference between running GraalVM's JavaScript in Native Image compared to the JVM? -In essence, the JavaScript engine of GraalVM is a plain Java application. -Running it on any JVM (JDK 21 or later) is possible, but, for a better result, it should be GraalVM JDK, or a compatible Oracle JDK or OpenJDK using the Graal Compiler. +### What is the difference between running GraalJS in Native Image compared to the JVM? +In essence, the GraalJS engine is a plain Java application. +Running it on any JVM (JDK 21 or later) is possible, but, for a better result, it should be a GraalVM JDK, or a compatible Oracle JDK using the Graal compiler. This mode gives the JavaScript engine full access to Java at runtime, but also requires the JVM to first (just-in-time) compile the JavaScript engine when executed, just like any other Java application. -Running in Native Image means that the JavaScript engine, including all its dependencies from, e.g., the JDK, is pre-compiled into a native executable. -This will tremendously speed up the startup of any JavaScript application, as GraalVM can immediately start to compile JavaScript code, without itself requiring to be compiled first. +Running in Native Image means that the JavaScript engine, including all its dependencies from, for example, the JDK, is precompiled into a native executable. +This will tremendously reduce the startup of any JavaScript application, as GraalVM can immediately start to compile JavaScript code, without itself requiring to be compiled first. This mode, however, will only give GraalVM access to Java classes known at the time of image creation. Most significantly, this means that the JavaScript-to-Java interoperability features are not available in this mode, as they would require dynamic class loading and execution of arbitrary Java code at runtime. -### Can npm packages be installed globally? -Node packages can be installed globally using `npm` and the `-g` option, both with the original Node.js implementation and GraalVM. - -While the original Node.js implementation has one main folder (`NODE/bin`) to put binaries and globally installed packages and their commandline tools, GraalVM has several: the main `GRAALVM/bin` folder, and separate folders for each language, e.g. `GRAALVM/jre/languages/js/bin`. -When installing npm packages globally in GraalVM, links to the executables e.g. for command line interface tools are put to the JavaScript-specific folder. -In order for globally installed packages to function properly, you might need to add `GRAALVM/jre/languages/js/bin` to your `$PATH`. - -Another option is to specify the global installation folder of `npm` by setting the `$PREFIX` environment variable, or by specifying the `--prefix` option when running `npm install`. - -For more details, see [Installing `npm` Packages Globally](NodeJS.md#installing-npm-packages-globally). - ## Errors ### TypeError: Access to host class com.myexample.MyClass is not allowed or does not exist Reason: -* You are trying to access a Java class that is not known to the `js` or `node` process, or is not among the allowed classes your code can access. +* You are trying to access a Java class that is unknown to the `js` process, or is not among the allowed classes that your code can access. Solution: * Ensure there is no typo in the class name. -* Ensure the class is on the classpath. Use the `--vm.cp=` option of the launchers. -* Ensure access to the class is permitted, by having `@HostAccess.Export` on your class and/or the `Context.Builder.allowHostAccess()` set to a permissive setting. See [JavaDoc of org.graalvm.polyglot.Context](https://graalvm.org/truffle/javadoc/org/graalvm/polyglot/Context.html). +* Ensure the class is on the class path. Use the `--vm.cp=` option. +* Ensure access to the class is permitted, by having a `@HostAccess.Export` annotation on your class and/or the `Context.Builder.allowHostAccess()` set to a permissive setting. See [org.graalvm.polyglot.Context](https://graalvm.org/truffle/javadoc/org/graalvm/polyglot/Context.html). ### TypeError: UnsupportedTypeException ``` @@ -143,7 +103,7 @@ TypeError: execute on JavaObject[Main$$Lambda$63/1898325501@1be2019a (Main$$Lamb ``` Reason: -* GraalVM JavaScript in some cases does not allow concrete callback types when calling from JavaScript to Java. A Java function expecting, e.g., a `Value` object, might fail with the quoted error message due to that. +* GraalJS in some cases does not allow concrete callback types when calling from JavaScript to Java. A Java function expecting, for example, a `Value` object, might fail with the quoted error message due to that. Solution: * Change the signature in the Java callback method. @@ -181,14 +141,14 @@ TypeError: execute on JavaObject[Main$$Lambda$62/953082513@4c60d6e9 (Main$$Lambd ``` Reason: -* You are trying to execute an operation (a message) on a polyglot object that this object does not handle. E.g., you are calling `Value.execute()` on a non-executable object. -* A security setting (e.g., `org.graalvm.polyglot.HostAccess`) might prevent the operation. +* You are trying to execute an operation (a message) on a polyglot object that this object does not handle. For example, you are calling `Value.execute()` on a non-executable object. +* A security setting (for example, `org.graalvm.polyglot.HostAccess`) might prevent the operation. Solution: * Ensure the object (type) in question does handle the respective message. -* Specifically, ensure the JavaScript operation you try to execute on a Java type is possible semantically in Java. For instance, while you can `push` a value to an array in JavaScript and thus automatically grow the array, arrays in Java are of fixed length and trying to push to them will result in a `Message not supported` failure. You might want to wrap Java objects for such cases, e.g., as a `ProxyArray`. -* Ensure access to the class is permitted, by having `@HostAccess.Export` on your class and/or the `Context.Builder.allowHostAccess()` set to a permissive setting. See [JavaDoc of org.graalvm.polyglot.Context](https://graalvm.org/truffle/javadoc/org/graalvm/polyglot/Context.html). -* Are you trying to call a Java Lambda expression or Functional Interface? Annotating the proper method with `@HostAccess.Export` can be a pitfall. While you can annotate the method the functional interface refers to, the interface itself (or the Lambda class created in the background) fails to be properly annotated and recognized as _exported_. See below for examples highlighting the problem and a working solution. +* Specifically, ensure the JavaScript operation you try to execute on a Java type is possible semantically in Java. For example, while you can `push` a value to an array in JavaScript and thus automatically grow the array, arrays in Java are of fixed length and trying to push to a Java array will result in a `Message not supported` failure. You might want to wrap Java objects for such cases, for example, as a `ProxyArray`. +* Ensure access to the class is permitted, by having a `@HostAccess.Export` annotation on your class and/or the `Context.Builder.allowHostAccess()` set to a permissive setting. See [org.graalvm.polyglot.Context](https://graalvm.org/truffle/javadoc/org/graalvm/polyglot/Context.html). +* Are you trying to call a Java Lambda expression or Functional Interface? Annotating the proper method with a `@HostAccess.Export` annotation can be a pitfall. While you can annotate the method to which the functional interface refers, the interface itself (or the Lambda class created in the background) fails to be properly annotated and recognized as _exported_. See below for examples highlighting the problem and a working solution. An example that triggers a `Message not supported` error with certain `HostAccess` settings, e.g., `HostAccess.EXPLICIT`: ```java @@ -209,10 +169,9 @@ public Callable lambda42 = () -> 42; ``` In the example above, the method `javaFn` is seemingly annotated with `@Export`, but the functional interface passed to `jsFn` is **not**, as the functional interface behaves like a wrapper around `javaFn`, thus hiding the annotation. -Neither is `lambda42` properly annotated - that pattern annotates the _field_ `lambda42`, not its executable function in the generated lambda class. +Neither is `lambda42` properly annotated—that pattern annotates the _field_ `lambda42`, nor its executable function in the generated lambda class. In order to add the `@Export` annotation to a functional interface, use this pattern instead: - ```java import java.util.function.Function; import org.graalvm.polyglot.Context; @@ -242,8 +201,7 @@ public class FAQ { ``` Another option is to allow access to `java.function.Function`'s `apply` method. -However, note that this allows access to _ALL_ instances of this interface - in most production setups, this will be too permissive and open potential security holes. - +However, note that this allows access to _ALL_ instances of this interface—in most production environments, this will be too permissive and open potential security holes. ```java HostAccess ha = HostAccess.newBuilder(HostAccess.EXPLICIT) //warning: too permissive for use in production @@ -261,9 +219,9 @@ Execution only in interpreted mode will strongly impair guest application perfor To disable this warning, use the '--engine.WarnInterpreterOnly=false' option or the '-Dpolyglot.engine.WarnInterpreterOnly=false' system property. ``` -To resolve this issue, use [GraalVM](https://www.graalvm.org/downloads/) or see the [Run GraalVM JavaScript on a Stock JDK guide](RunOnJDK.md) for instructions how to set up the Graal JIT compiler on a compatible Graal-enabled stock JDK. +To resolve this, use [GraalVM](https://www.graalvm.org/downloads/) or see how to [Run GraalJS on a Stock JDK guide](RunOnJDK.md) for instructions on how to set up the Graal compiler on a compatible Graal-enabled stock JDK. -Nevertheless, if this is intentional, you can disable the warning and continue to run with degraded performance by setting the option described above, either via the command line or by using the `Context.Builder`, for example: +Nevertheless, if this is intentional, you can disable the warning and continue to run with degraded performance by setting the above mentioned option, either via the command line or using the `Context.Builder`, for example: ```java try (Context ctx = Context.newBuilder("js") .option("engine.WarnInterpreterOnly", "false") @@ -280,4 +238,4 @@ try (Engine engine = Engine.newBuilder() ctx.eval("js", "console.log('Greetings!');"); } } -``` +``` \ No newline at end of file diff --git a/docs/user/JavaInteroperability.md b/docs/user/JavaInteroperability.md index d9340de8a61..f1a85f9c50c 100644 --- a/docs/user/JavaInteroperability.md +++ b/docs/user/JavaInteroperability.md @@ -4,51 +4,37 @@ toc_group: js link_title: Java Interoperability permalink: /reference-manual/js/JavaInteroperability/ --- + # Java Interoperability -This documentation shows you how to enable interoperability with Java and possible JavaScript-to-Java embedding scenarions. +This documentation shows you how to enable interoperability with Java and possible JavaScript-to-Java embedding scenarios. ## Enabling Java Interoperability As of GraalVM for JDK 21, all necessary artifacts can be downloaded directly from Maven Central. All artifacts relevant to embedders can be found in the Maven dependency group [`org.graalvm.polyglot`](https://central.sonatype.com/namespace/org.graalvm.polyglot). -Here is an example Maven dependency setup that you can put into your Java project: - +To embed JavaScript in a Java application, add the following dependencies to the Maven configuration file: ```xml org.graalvm.polyglot polyglot - ${graalvm.version} + ${graaljs.version} org.graalvm.polyglot js - ${graalvm.version} + ${graaljs.version} pom ``` - -The JavaScript (GraalJS) and Node.js runtimes are also available as standalone distributions. -There are two runtime options to choose from: a Native Image compiled native launcher or a JVM-based runtime (included). -To enable interoperability with Java, use a JVM-based standalone: it has a `-jvm` suffix in a name, for example: `graaljs-jvm---.tar.gz`. See [Getting Started](README.md#getting-started). - -The following examples assume the last setup is used. - -### Classpath - -To load Java classes you need to have them on the Java classpath. -You can specify the classpath with the `--vm.classpath=` option (or short: `--vm.cp=`): -```shell -node --vm.cp=/my/class/path -js --vm.cp=/my/class/path -``` -The method `Java.addToClasspath()` can be used to programmatically add to the classpath at runtime. +The `pom` type is a requirement for a language dependency. +Learn more about the dependency setup in the [Java Interoperability guide](JavaInteroperability.md). ## Polyglot Context -The preferred method of launching GraalVM JavaScript with Java interop support is via polyglot `Context`. -For that, a new `org.graalvm.polyglot.Context` is built with the `hostAccess` option allowing access and a `hostClassLookup` predicate defining the Java classes you allow access to: +The preferred method of embedding JavaScript in Java is via `Context`. +For that, a new `org.graalvm.polyglot.Context` is built with the `hostAccess` option allowing access and a `hostClassLookup` predicate defining the Java classes you allow access to: ```java Context context = Context.newBuilder("js") .allowHostAccess(HostAccess.ALL) @@ -58,14 +44,12 @@ Context context = Context.newBuilder("js") context.eval("js", jsSourceCode); ``` -See the [Embedding Reference](https://www.graalvm.org/reference-manual/embed-languages/) on how to interact with a guest language like JavaScript from a Java host application. -The [Polyglot Programming](https://www.graalvm.org/reference-manual/polyglot-programming/) guide can also be of help in that area. +See the [Guide to Embedding Languages](https://www.graalvm.org/reference-manual/embed-languages/) on how to interact with a guest language such as JavaScript from a Java host application. ## ScriptEngine (JSR 223) -The `org.graalvm.polyglot.Context` is the preferred execution method for interoperability with GraalVM's languages and tools. -In addition, JavaScript running on GraalVM is fully compatible with JSR 223 and supports the `ScriptEngine API`. -Internally, the GraalVM's JavaScript ScriptEngine wraps a polyglot context instance: +JavaScript running on a GraalVM JDK is fully compatible with JSR 223 and supports the `ScriptEngine API`. +Internally, the GraalVM's JavaScript ScriptEngine wraps a polyglot `Context` instance: ```java ScriptEngine eng = new ScriptEngineManager() .getEngineByName("graal.js"); @@ -74,66 +58,65 @@ Invocable inv = (Invocable) eng; Object result = inv.invokeMethod(fn, "call", fn); ``` -See the [ScriptEngine guide](ScriptEngine.md) for more details on how to use it from GraalVM JavaScript. +See the [ScriptEngine guide](ScriptEngine.md) for more details on how to use it from GraalJS. ## Access Java from JavaScript + GraalVM provides a set of features to allow interoperability from `JavaScript` to `Java`. -While Rhino, Nashorn, and GraalVM JavaScript have a mostly comparable overall feature set, they differ in exact syntax, and, partly, semantics. +While Rhino, Nashorn, and GraalJS have a mostly comparable overall feature set, they differ in exact syntax, and, partly, semantics. ### Class Access -To access a Java class, GraalVM JavaScript supports the `Java.type(typeName)` function: +To access a Java class, GraalJS supports the `Java.type(typeName)` function: ```js var FileClass = Java.type('java.io.File'); ``` -By default, Java classes are not automatically mapped to global variables, e.g., there is no `java` global property in GraalVM JavaScript. -Existing code accessing, e.g., `java.io.File`, should be rewritten to use the `Java.type(name)` function: - +If the host class lookup is allowed (`allowHostClassLookup`), the `java` global property is available by default. +Existing code accessing, for example, `java.io.File`, should be rewritten to use the `Java.type(name)` function: ```js -//GraalVM JavaScript compliant syntax +// GraalJS (and Nashorn) compliant syntax var FileClass = Java.type("java.io.File"); -//backwards-compatible syntax +// Backwards-compatible syntax var FileClass = java.io.File; ``` -GraalVM JavaScript provides `Packages`, `java`, and similar global properties for compatibility. +GraalJS provides `Packages`, `java`, and similar global properties for compatibility. However, explicitly accessing the required class with `Java.type` is preferred whenever possible for two reasons: -1. It allows resolving the class in one step rather than trying to resolve each property as a class. +1. It resolves the class in one step instead of trying to resolve each property as a class. 2. `Java.type` immediately throws a `TypeError` if the class cannot be found or is not accessible, rather than silently treating an unresolved name as a package. -The `js.java-package-globals` flag can be used to deactivate the global fields of Java packages (set `false` to avoid creation of the fields; default is `true`). +The `js.java-package-globals` flag can be used to deactivate the global fields of Java packages (set to `false` to avoid creation of the fields; default is `true`). ### Constructing Java Objects -Java objects can be constructed with JavaScript's `new` keyword: +A Java object can be constructed with JavaScript's `new` keyword: ```js var FileClass = Java.type('java.io.File'); var file = new FileClass("myFile.md"); ``` ### Field and Method Access -Static fields of a Java class, or fields of a Java object, can be accessed like JavaScript properties: +The static fields of a Java class, or the fields of a Java object, can be accessed like JavaScript properties: ```js var JavaPI = Java.type('java.lang.Math').PI; ``` Java methods can be called like JavaScript functions: - ```js var file = new (Java.type('java.io.File'))("test.md"); var fileName = file.getName(); ``` ### Conversion of Method Arguments + JavaScript is defined to operate on the `double` number type. -GraalVM JavaScript might internally use additional Java data types for performance reasons (e.g., the `int` type). +GraalJS might internally use additional Java data types for performance reasons (for example, the `int` type). When calling Java methods, a value conversion might be required. -This happens when the Java method expects a `long` parameter, and an `int` is provided from GraalVM JavaScript (`type widening`). +This happens when the Java method expects a `long` parameter, and an `int` is provided from GraalJS (`type widening`). If this conversion causes a lossy conversion, a `TypeError` is thrown: - ```java //Java void longArg (long arg1); @@ -154,10 +137,10 @@ javaObject.intArg(1.1); //lossy conversion, TypeError! Note how the argument values have to fit into the parameter types. You can override this behavior using custom [target type mappings](https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/HostAccess.Builder.html#targetTypeMapping-java.lang.Class-java.lang.Class-java.util.function.Predicate-java.util.function.Function-). -### Selection of Method +### Method Selection + Java allows overloading of methods by argument types. When calling from JavaScript to Java, the method with the narrowest available type that the actual argument can be converted to without loss is selected: - ```java //Java void foo(int arg); @@ -174,10 +157,9 @@ javaObject.foo(Math.pow(2,32)); // will call foo(long); ``` To override this behavior, an explicit method overload can be selected using the `javaObject['methodName(paramTypes)']` syntax. -Parameter types need to be comma-separated without spaces, and Object types need to be fully qualified (e.g., `'get(java.lang.String,java.lang.String[])'`). +Parameter types need to be comma-separated without spaces, and object types need to be fully qualified (for example, `'get(java.lang.String,java.lang.String[])'`). Note that this is different from Nashorn which allows extra spaces and simple names. -In the example above, one might always want to call, e.g., `foo(long)`, even when `foo(short)` can be reached with lossless conversion (`foo(1)`): - +In the example above, one might always want to call, for example, `foo(long)`, even when `foo(short)` can be reached with lossless conversion (`foo(1)`): ```js javaObject['foo(int)'](1); javaObject['foo(long)'](1); @@ -188,7 +170,6 @@ Note that the argument values still have to fit into the parameter types. You can override this behavior using custom [target type mappings](https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/HostAccess.Builder.html#targetTypeMapping-java.lang.Class-java.lang.Class-java.util.function.Predicate-java.util.function.Function-). An explicit method selection can also be useful when the method overloads are ambiguous and cannot be automatically resolved as well as when you want to override the default choice: - ```java //Java void sort(List array, Comparator callback); @@ -213,40 +194,40 @@ javaObject['consumeArray(java.lang.Object[])'](array); ``` Note that there is currently no way to explicitly select constructor overloads. -Future versions of GraalVM JavaScript might lift that restriction. +Future versions of GraalJS might lift that restriction. ### Package Access -GraalVM JavaScript provides a `Packages` global property: +GraalJS provides a `Packages` global property: ```shell > Packages.java.io.File JavaClass[java.io.File] ``` ### Array Access -GraalVM JavaScript supports the creation of Java arrays from JavaScript code. -Both the patterns suggested by Rhino and Nashorn are supported: +GraalJS supports the creation of Java arrays from JavaScript code. +Both the patterns suggested by Rhino and Nashorn are supported: ```js //Rhino pattern var JArray = Java.type('java.lang.reflect.Array'); var JString = Java.type('java.lang.String'); var sarr = JArray.newInstance(JString, 5); - -//Nashorn pattern +``` +```js +// Nashorn pattern var IntArray = Java.type("int[]"); var iarr = new IntArray(5); ``` The arrays created are Java types, but can be used in JavaScript code: - ```js iarr[0] = iarr[iarr.length] * 2; ``` ### Map Access -In GraalVM JavaScript you can create and access Java Maps, e.g., `java.util.HashMap`: +In GraalJS you can create and access Java Maps, for example, `java.util.HashMap`: ```js var HashMap = Java.type('java.util.HashMap'); var map = new HashMap(); @@ -254,8 +235,7 @@ map.put(1, "a"); map.get(1); ``` -GraalVM JavaScript supports iterating over such maps similar to Nashorn: - +GraalJS supports iterating over such maps similar to Nashorn: ```js for (var key in map) { print(key); @@ -264,8 +244,8 @@ for (var key in map) { ``` ### List Access -In GraalVM JavaScript you can create and access Java Lists, e.g., `java.util.ArrayList`: +In GraalJS you can create and access Java Lists, for example, `java.util.ArrayList`: ```js var ArrayList = Java.type('java.util.ArrayList'); var list = new ArrayList(); @@ -280,47 +260,52 @@ for (var idx in list) { ``` ### String Access -GraalVM JavaScript can create Java strings with Java interoperability. -The length of the string can be queried with the `length` property (note that `length` is a value property and cannot be called as a function): +GraalJS can create Java strings with Java interoperability. +The length of the string can be queried with the `length` property (note that `length` is a value property and cannot be called as a function): ```js var javaString = new (Java.type('java.lang.String'))("Java"); javaString.length === 4; ``` -Note that GraalVM JavaScript uses Java strings internally to represent JavaScript strings, so the above code and the JavaScript string literal `"Java"` are actually not distinguishable. +Note that GraalJS uses Java strings internally to represent JavaScript strings, so the above code and the JavaScript string literal `"Java"` are actually not distinguishable. ### Iterating Properties -Properties (fields and methods) of Java classes and Java objects can be iterated with a JavaScript `for..in` loop: - var m = Java.type('java.lang.Math') - for (var i in m) { print(i); } - > E - > PI - > abs - > sin - > ... +Properties (fields and methods) of Java classes and Java objects can be iterated with a JavaScript `for..in` loop: +``` +var m = Java.type('java.lang.Math') +for (var i in m) { print(i); } +> E +> PI +> abs +> sin +> ... +``` ## Access to JavaScript Objects from Java + JavaScript objects are exposed to Java code as instances of `com.oracle.truffle.api.interop.java.TruffleMap`. This class implements Java's `Map` interface. ### JavaImporter -The `JavaImporter` feature is available only in Nashorn compatibility mode (`js.nashorn-compat` option). + +The `JavaImporter` feature is available only in Nashorn compatibility mode (with the `js.nashorn-compat` option). ### Console Output of Java Classes and Java Objects -GraalVM JavaScript provides both `print` and `console.log`. -GraalVM JavaScript provides a `print` built-in function compatible with Nashorn. +GraalJS provides both `print` and `console.log`. + +GraalJS provides a `print` built-in function compatible with Nashorn. The `console.log` is provided by Node.js directly. It does not provide special treatment of interop objects. -Note that the default implementation of `console.log` on GraalVM JavaScript is just an alias for `print`, and Node's implementation is only available when running on Node.js. +Note that the default implementation of `console.log` on GraalJS is just an alias for `print`, and Node's implementation is only available when running on Node.js. ### Exceptions + Exceptions thrown in Java code can be caught in JavaScript code. They are represented as Java objects: - ```js try { Java.type('java.lang.Class') @@ -332,12 +317,13 @@ try { ## Promises -GraalVM JavaScript provides support for interoperability between JavaScript `Promise` objects and Java. +GraalJS provides support for interoperability between JavaScript `Promise` objects and Java. Java objects can be exposed to JavaScript code as _thenable_ objects, allowing JavaScript code to `await` Java objects. Moreover, JavaScript `Promise` objects are regular JavaScript objects, and can be accessed from Java using the mechanisms described in this document. This allows Java code to be called back from JavaScript when a JavaScript promise is resolved or rejected. ### Creating JavaScript `Promise` Objects That Can Be Resolved from Java + JavaScript applications can create `Promise` objects delegating to Java the resolution of the `Promise` instance. This can be achieved from JavaScript by using a Java object as the ["executor"](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) function of the JavaScript `Promise`. For example, Java objects implementing the following functional interface can be used to create new `Promise` objects: @@ -354,22 +340,24 @@ Any Java object implementing `PromiseExecutor` can be used to create a JavaScrip var myPromise = new Promise(javaExecutable).then(...); ``` -JavaScript `Promise` objects can be created not only using functional interfaces, but also using any other Java object that can be executed by the GraalVM JavaScript engine (for example, any Java object implementing the Polyglot [ProxyExecutable](https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/proxy/ProxyExecutable.html) interface). -More detailed example usages are available in the GraalVM JavaScript [unit tests](https://github.com/graalvm/graaljs/blob/master/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/AsyncInteropTest.java). +JavaScript `Promise` objects can be created not only using functional interfaces, but also using any other Java object that can be executed by GraalJS (for example, any Java object implementing the Polyglot [ProxyExecutable](https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/proxy/ProxyExecutable.html) interface). +More detailed example usages are available in the GraalJS [unit tests](https://github.com/graalvm/graaljs/blob/master/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/AsyncInteropTest.java). ### Using `await` with Java Objects + JavaScript applications can use the `await` expression with Java objects. This can be useful when Java and JavaScript have to interact with asynchronous events. -To expose a Java object to GraalVM JavaScript as a _thenable_ object, the Java object should implement a method called `then()` having the following signature: +To expose a Java object to GraalJS as a _thenable_ object, the Java object should implement a method called `then()` having the following signature: ```java void then(Value onResolve, Value onReject); ``` -When `await` is used with a Java object implementing `then()`, the GraalVM JavaScript runtime will treat the object as a JavaScript `Promise`. +When `await` is used with a Java object implementing `then()`, GraalJS will treat the object as a JavaScript `Promise`. The `onResolve` and `onReject` arguments are executable `Value` objects that should be used by the Java code to resume or abort the JavaScript `await` expression associated with the corresponding Java object. -More detailed example usages are available in the GraalVM JavaScript [unit tests](https://github.com/graalvm/graaljs/blob/master/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/AsyncInteropTest.java). +More detailed example usages are available in the GraalJS [unit tests](https://github.com/graalvm/graaljs/blob/master/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/AsyncInteropTest.java). ### Using JavaScript Promises from Java + `Promise` objects created in JavaScript can be exposed to Java code like any other JavaScript object. Java code can access such objects like normal `Value` objects, with the possibility to register new promise resolution functions using the `Promise`'s default `then()` and `catch()` functions. As an example, the following Java code registers a Java callback to be executed when a JavaScript promise resolves: @@ -379,21 +367,23 @@ Consumer javaThen = (value) -> System.out.println("Resolved from JavaScript: " + value); jsPromise.invokeMember("then", javaThen); ``` -More detailed example usages are available in the GraalVM JavaScript [unit tests](https://github.com/graalvm/graaljs/blob/master/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/AsyncInteropTest.java). + +More detailed example usages are available in the GraalJS [unit tests](https://github.com/graalvm/graaljs/blob/master/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/AsyncInteropTest.java). ## Multithreading -GraalVM JavaScript supports multithreading when used in combination with Java. More details about the GraalVM JavaScript multithreading model can be found in the [Multithreading](Multithreading.md) documentation. +GraalJS supports multithreading when used in combination with Java. +More details about the GraalJS multithreading model can be found in the [Multithreading](Multithreading.md) documentation. ## Extending Java classes -GraalVM JavaScript provides support for extending Java classes and interfaces using the `Java.extend` function. -Note that host access has to be enabled in the [polyglot context](#polyglot-context) for this feature to be available. +GraalJS provides support for extending Java classes and interfaces using the `Java.extend` function. +Note that host access has to be enabled in a [polyglot context](#polyglot-context) for this feature to be available. ### Java.extend + `Java.extend(types...)` returns a generated adapter Java class object that extends the specified Java class and/or interfaces. For example: - ```js var Ext = Java.extend(Java.type("some.AbstractClass"), Java.type("some.Interface1"), @@ -409,7 +399,6 @@ impl.superclassMethod(); Super methods can be called via `Java.super(adapterInstance)`. See a combined example: - ```js var sw = new (Java.type("java.io.StringWriter")); var FilterWriterAdapter = Java.extend(Java.type("java.io.FilterWriter")); @@ -432,7 +421,6 @@ print(sw); // ABCDEFGHIJKLMNO ``` Note that in the `nashorn-compat` mode, you can also extend interfaces and abstract classes using a new operator on a type object of an interface or an abstract class: - ```js // --experimental-options --js.nashorn-compat var JFunction = Java.type('java.util.function.Function'); @@ -440,4 +428,10 @@ var JFunction = Java.type('java.util.function.Function'); apply: function(x) { return x * x; } }); sqFn.apply(6); // 36 -``` \ No newline at end of file +``` + +### Related Documentation + +* [Guide to Embedding Languages](https://www.graalvm.org/reference-manual/embed-languages/) +* [GraalJS Compatibility](JavaScriptCompatibility.md) +* [Multithreading Support](Multithreading.md) \ No newline at end of file diff --git a/docs/user/JavaScriptCompatibility.md b/docs/user/JavaScriptCompatibility.md index 34603b0ce53..fab3fd5bbce 100644 --- a/docs/user/JavaScriptCompatibility.md +++ b/docs/user/JavaScriptCompatibility.md @@ -1,31 +1,31 @@ --- layout: docs toc_group: js -link_title: JavaScript Compatibility +link_title: GraalJS Compatibility permalink: /reference-manual/js/JavaScriptCompatibility/ --- -# JavaScript Compatibility -GraalVM provides an ECMAScript-compliant JavaScript language runtime. +# GraalJS Compatibility + +GraalJS is an ECMAScript-compliant JavaScript language runtime. This document explains the public API it presents for user applications written in JavaScript. * [ECMAScript Language Compliance](#ecmascript-language-compliance) * [Compatibility Extensions](#compatibility-extensions) -* [GraalVM JavaScript Extensions](#graalvm-javascript-extensions) +* [GraalJS Extensions](#graalvm-javascript-extensions) ## ECMAScript Language Compliance -GraalVM JavaScript implements JavaScript as prescribed in the ECMAScript (ECMA-262) specification. -It is fully compatible with the [ECMAScript 2023 specification](https://262.ecma-international.org/14.0/) (sometimes referred to as the 14th edition). +GraalJS implements the ECMAScript (ECMA-262) specification and is fully compatible with the [ECMAScript 2024 specification](https://262.ecma-international.org/) (sometimes referred to as the 15th edition). New features are frequently added to GraalVM when they are confirmed to be part of ECMAScript 2024, see the [CHANGELOG.md](https://github.com/oracle/graaljs/blob/master/CHANGELOG.md) for details. -Older versions starting from ECMAScript 5 can be enabled with a config flag (by number: `--js.ecmascript-version=5` or by year: `--js.ecmascript-version=2019`). -In a production setup you might consider specifying a fixed ECMAScript version to be used, as future versions of GraalVM JavaScript will use newer versions of the specification once available. +Older versions starting from ECMAScript 5 can be enabled with a configuration option (by number: `--js.ecmascript-version=5` or by year: `--js.ecmascript-version=2024`). +In a production environment, you might consider specifying a fixed ECMAScript version to be used, as future versions of GraalJS will use newer versions of the specification once available. -GraalVM JavaScript provides the following function objects in the global scope as specified by ECMAScript, representing the JavaScript core library: +GraalJS provides the following function objects in the global scope as specified by ECMAScript, representing the JavaScript core library: Array, ArrayBuffer, Boolean, DataView, Date, Error, Function, JSON, Map, Math, Number, Object, Promise, Proxy, Reflect, RegExp, Set, SharedArrayBuffer, String, Symbol, TypedArray, WeakMap, and WeakSet. -Additional objects are available under flags, for instance `Temporal` (flag: `--js.temporal`). -Run `js --help` or `js --help:languages` for the list of available flags. +Additional objects are available under options, for example, `--js.temporal`. +Run `js --help` for the list of available options. Several of these function objects and some of their members are only available when a certain version of the specification is selected for execution. For a list of methods provided, inspect the ECMAScript specification. @@ -33,9 +33,8 @@ Extensions to the specification are specified below. ### Internationalization API (ECMA-402) -GraalVM JavaScript comes with an implementation of the [ECMA-402 Internationalization API](https://tc39.github.io/ecma402), enabled by default (can be disabled using the following flag: `--js.intl-402=false`). +GraalJS comes with an implementation of the [ECMA-402 Internationalization API](https://tc39.github.io/ecma402), enabled by default (can be disabled using the following option: `--js.intl-402=false`). This includes the following extensions: - - `Intl.Collator` - `Intl.DateTimeFormat` - `Intl.DisplayNames` @@ -46,28 +45,28 @@ This includes the following extensions: - `Intl.RelativeTimeFormat` - `Intl.Segmenter` -The functionality of a few other built-ins, like `toLocaleString`, is also updated according to the ECMA-402 specification. +The functionality of a few other built-ins, such as `toLocaleString`, is also updated according to the ECMA-402 specification. ### JavaScript Modules -GraalVM JavaScript supports modules as defined by ECMAScript 6 and later. -Be aware that the support for this feature grew and still grows over time. Be sure to use the latest ECMAScript version for the all the latest features. +GraalJS supports modules as defined by ECMAScript 6 and later. +Be aware that the support for this feature continues to increase. +Be sure to use the latest ECMAScript version for the all the latest features. -When loading modules via a polyglot `Source`, you can use the inofficial `application/javascript+module` mime type to specify you are loading a module. -When loading with JavaScript code from a file, make sure the module is loaded from a file with the `.mjs` extension. +When loading modules via a polyglot `Source`, you can use the unofficial `application/javascript+module` MIME type to specify that you are loading a module. +When loading with JavaScript code from a file, make sure the module is loaded from a file with the _.mjs_ extension. Loading with the `import` keyword is not limited by that, and can `import` from a file of any extension. ## Compatibility Extensions -The following objects and methods are available in GraalVM JavaScript for compatibility with other JavaScript engines. +The following objects and methods are available in GraalJS for compatibility with other JavaScript engines. Note that the behavior of such methods might not strictly match the semantics of those methods in all existing engines. ### Language Features #### Conditional Catch Clauses -GraalVM JavaScript supports conditional catch clauses if the `js.syntax-extensions` option is enabled: - +GraalJS supports conditional catch clauses if the `js.syntax-extensions` option is enabled: ```js try { myMethod(); // can throw @@ -81,11 +80,9 @@ try { ### Global Properties #### `load(source)` - - loads (parses and executes) the specified JavaScript source code Source can be of type: - * a String: the path of the source file or a URL to execute. * `java.lang.URL`: the URL is queried for the source code to execute if the `js.load-from-url` option is set to `true`. * `java.io.File`: the file is read for the source code to execute. @@ -96,7 +93,7 @@ Source can be of type: #### `print(...arg)` and `printErr(...arg)` -- prints the arguments on the console (stdout and stderr, respectively) +- prints the arguments on the console (`stdout` and `stderr`, respectively) - provides a best-effort human readable output `print` and `printErr` are available by default and can be deactivated by setting the `js.print` option to `false`. @@ -106,14 +103,13 @@ Source can be of type: A global `console` object is provided that offers several methods for debugging purposes. These methods strive to provide similar functionality as provided in other engines, but do not guarantee identical results. -Note that those methods behave differently when GraalVM JavaScript is executed in Node.js mode (i.e., the `node` executable is started instead of `js`). +Note that those methods behave differently when GraalJS is executed in Node.js mode (for example, the `node` executable is started instead of `js`). Node.js provides its own implementation that is used instead. - * `console.log`, `console.info`, and `console.debug`: an alias for `print(...arg)` * `console.error`, and `console.warn`: similar to `print`, but using the error IO stream * `console.assert(check, message)`: prints `message` when `check` is falsy * `console.clear`: clears the console window if possible -* `console.count()`, and `console.countReset()`: counts and print how many times it has been called, or resets this counter +* `console.count()`, and `console.countReset()`: counts and prints how many times it has been called, or resets this counter * `console.group`, and `console.groupEnd`: increases or decreases the indentation for succeeding outputs to the console * `console.time()`, `console.timeLog()`, and `console.timeEnd()`: starts a timer, prints the duration the timer has been active, or prints the duration and stops the timer, respectively @@ -178,7 +174,8 @@ This functionality is deprecated in most JavaScript engines. In recent ECMAScript versions, getters and setters are natively supported by the language. ### Nashorn Scripting Mode -GraalVM JavaScript provides a scripting mode compatible with the one provided by the Nashorn engine. + +GraalJS provides a scripting mode compatible with the one provided by the Nashorn engine. It is enabled with the `js.scripting` option. Make sure to have `--experimental-options` set: ```shell js --experimental-options --js.scripting=true @@ -188,14 +185,13 @@ In scripting mode, several properties and functions are added to the global obje There are migration guides available for code previously targeted to the [Nashorn](https://github.com/graalvm/graaljs/blob/master/docs/user/NashornMigrationGuide.md) or [Rhino](https://github.com/graalvm/graaljs/blob/master/docs/user/RhinoMigrationGuide.md) engines. -## GraalVM JavaScript Extensions +## GraalJS Extensions ### Graal Object The `Graal` object is provided as a property of the global object. It provides Graal-specific information. -The existence of the property can be used to identify whether the GraalVM JavaScript engine is the current language engine: - +The existence of the property can be used to identify whether GraalJS is the current language engine: ```js if (typeof Graal != 'undefined') { print(Graal.versionECMAScript); @@ -204,11 +200,11 @@ if (typeof Graal != 'undefined') { } ``` -The Graal object is available in GraalVM JavaScript by default, unless deactivated by an option (`js.graal-builtin=false`). +The Graal object is available in GraalJS by default, unless deactivated by an option (`js.graal-builtin=false`). #### `Graal.versionECMAScript` -- provides the version number (year value) of GraalVM JavaScript's ECMAScript compatibility mode. +- provides the version number (year value) of the GraalJS ECMAScript compatibility mode #### `Graal.versionGraalVM` @@ -216,9 +212,9 @@ The Graal object is available in GraalVM JavaScript by default, unless deactivat #### `Graal.isGraalRuntime()` -- provides whether GraalVM JavaScript is executed on a GraalVM-enabled runtime -- If `true`, hot code is compiled by the GraalVM compiler, resulting in high peak performance. -- If `false`, GraalVM JavaScript will not be optimized by the GraalVM Compiler, typically resulting in lower performance. +- indicates if GraalJS is executed on a GraalVM-enabled runtime +- If `true`, hot code is compiled by the Graal compiler, resulting in high peak performance. +- If `false`, GraalJS will not be optimized by the Graal Compiler, typically resulting in lower performance. ### `Graal.setUnhandledPromiseRejectionHandler(handler)` @@ -229,23 +225,20 @@ The Graal object is available in GraalVM JavaScript by default, unless deactivat ### Java The `Java` object is only available when [host class lookup](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.Builder.html#allowHostClassLookup-java.util.function.Predicate-) is allowed. -In order to access Java host classes and its members, they first need to be allowed by the [host access policy](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/HostAccess.html), and when running from a Native Image, be registered for [run time reflection](https://www.graalvm.org/latest/reference-manual/native-image/dynamic-features/Reflection/). +To access Java host classes and its members, they first need to be allowed by the [host access policy](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/HostAccess.html), and when running from a native executable, be registered for [runtime reflection](https://www.graalvm.org/latest/reference-manual/native-image/dynamic-features/Reflection/). -Note that some functions require the Nashorn compatibility mode flag to be set. -When running from the JVM standalone distribution, this flag can be set with: -```shell -js --experimental-options --js.nashorn-compat=true -``` +Note that some functions require the Nashorn compatibility mode to be set (`--js.nashorn-compat=true`). #### `Java.type(className)` -`Java.type` loads the specified Java class and returns a constructible object that has the static members (i.e. methods and fields) of the class and can be used with the `new` keyword to construct new instances: +`Java.type` loads the specified Java class and returns a constructible object that has the static members (for example, methods and fields) of the class and can be used with the `new` keyword to construct new instances: ```js var BigDecimal = Java.type('java.math.BigDecimal'); var point1 = new BigDecimal("0.1"); var two = BigDecimal.TWO; console.log(point1.multiply(two).toString()); ``` + Note that when used directly with the `new` operator, `Java.type(...)` needs to be enclosed in parentheses: ```js console.log(new (Java.type('java.math.BigDecimal'))("1.1").pow(15)); @@ -262,10 +255,9 @@ In many cases, this is not necessary; you can typically use the Java data struct `Java.to` converts the argument to the Java type. The source object `jsData` is expected to be a JavaScript array, or an array-like object with a `length` property. -The target `javaType` can either be a String (e.g. `"int[]"`) or a type object (e.g., `Java.type("int[]")`). +The target `javaType` can either be a String (for example, an `"int[]"`) or a type object (such as `Java.type("int[]")`). Valid target types are Java arrays. When the target type is omitted, it defaults to `Object[]`. - ```js var jsArray = ["a", "b", "c"]; var stringArrayType = Java.type("java.lang.String[]"); @@ -275,7 +267,7 @@ var javaArray = Java.to(jsArray); assertEquals('class java.lang.Object[]', String(javaArray.getClass())); ``` -The conversion methods as defined by ECMAScript (e.g., `ToString` and `ToDouble`) are executed when a JavaScript value has to be converted to a Java type. +The conversion methods as defined by ECMAScript (for example, `ToString` and `ToDouble`) are executed when a JavaScript value has to be converted to a Java type. Lossy conversion is disallowed and results in a `TypeError`. #### `Java.isJavaObject(obj)` @@ -332,7 +324,8 @@ function helloWorld() { print("Hello, JavaScript world"); } Polyglot.export("helloJSWorld", helloWorld); ``` -If the polyglot bindings already had a value identified by `key`, it is overwritten with the new value. The `value` may be any valid Polyglot value. +If the polyglot bindings already had a value identified by `key`, it is overwritten with the new value. +The `value` may be any valid Polyglot value. - throws a `TypeError` if `key` is not a String or is missing @@ -352,11 +345,11 @@ If no language has exported a value identified by `key`, `undefined` is returned - parses and evaluates the `sourceCode` with the interpreter identified by `languageId` -The value of `sourceCode` is expected to be a String (or convertable to one). +The value of `sourceCode` is expected to be a String (or convertible to one). - returns the evaluation result, depending on the `sourceCode` and/or the semantics of the language evaluated: ```js -var rArray = Polyglot.eval('R', 'runif(1000)'); +var pyArray = Polyglot.eval('python', 'import random; [random.uniform(0.0, 1.0) for _ in range(1000)]'); ``` Exceptions can occur when an invalid `languageId` is passed, when the `sourceCode` cannot be evaluated by the language, or when the executed program throws one. @@ -365,7 +358,7 @@ Exceptions can occur when an invalid `languageId` is passed, when the `sourceCod - parses the file `sourceFileName` with the interpreter identified by `languageId` -The value of `sourceFileName` is expected to be a String (or convertable to one), representing a file reachable by the current path. +The value of `sourceFileName` is expected to be a String (or convertible to one), representing a file reachable by the current path. - returns an executable object, typically a function: ```js @@ -373,7 +366,7 @@ var rFunc = Polyglot.evalFile('R', 'myExample.r'); var result = rFunc(); ``` -Exceptions can occur when an invalid `languageId` is passed, when the file identified by `sourceFileName` cannot be found, or when the language throws an exception during parsing (parse time errors, e.g. syntax errors). +Exceptions can occur when an invalid `languageId` is passed, when the file identified by `sourceFileName` cannot be found, or when the language throws an exception during parsing (parse time errors, for example, syntax errors). Exceptions thrown by the evaluated program are only thrown once the resulting function is evaluated. The `Polyglot.evalFile` function is available by default when the `Polyglot` builtin is available, unless deactivated by setting the `js.polyglot-evalfile` option to `false`. @@ -381,16 +374,16 @@ It is also available when `js.debug-builtin` is activated. ### Debug -- requires starting the engine with the `js.debug-builtin` flag +- requires starting the engine with the `js.debug-builtin` option -`Debug` is a GraalVM JavaScript specific function object that provides functionality for debugging JavaScript code and the GraalVM JavaScript compiler. +`Debug` is a GraalJS specific function object that provides functionality for debugging JavaScript code and the JavaScript engine. This API might change without notice. Do not use for production purposes. ### Global Functions #### `printErr(...arg)` -- behaves identical to `print` +- behaves identically to `print` The only difference is that the error stream is used to print to, instead of the default output stream. @@ -407,3 +400,7 @@ Source can be of type: * all other types: the source is converted to a String. The value of `arguments` is provided to the loaded code upon execution. + +### Related Documentation + +* [Java Interoperability](JavaInteroperability.md) \ No newline at end of file diff --git a/docs/user/Modules.md b/docs/user/Modules.md index 4897dafa94d..fe7479f3434 100644 --- a/docs/user/Modules.md +++ b/docs/user/Modules.md @@ -4,42 +4,38 @@ toc_group: js link_title: Using JavaScript Modules and Packages permalink: /reference-manual/js/Modules/ --- -# Using JavaScript Modules and Packages in GraalVM JavaScript -GraalVM JavaScript is compatible with the latest ECMAScript standard, and can be executed in a variety of embedding scenarios such as Java-based applications or Node.js. -Depending on the GraalVM's JavaScript embedding scenario, JavaScript packages and modules may be used in different ways. +# Using JavaScript Modules and Packages in GraalJS -## Node.js +GraalJS is compatible with the latest ECMAScript standard, and can be run in a variety of Java-based embedding scenarios. +Depending on the embedding, JavaScript packages and modules may be used in different ways. -GraalVM ships with a specific Node.js version that it is compatible with. -Applications can therefore freely import and use NPM packages compatible with the supported Node.js version, including CommonJS, ES modules, and modules that use native bindings. -To check and verify the Node.js version supported by GraalVM, simply run `bin/node --version`. +## Java Embedding via `Context` API -## Java-based Applications (`Context` API) - -When embedded in a Java application (using the `Context` API), GraalVM JavaScript can execute JavaScript applications and modules that _do not_ depend on Node.js' built-in modules such as `'fs'`, `'events'`, or `'http'` or Node.js-specific functions such as `setTimeout()` or `setInterval()`. +When embedded in a Java application (using the [`Context` API](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.html)), GraalJS can execute JavaScript applications and modules that _do not_ depend on Node.js' built-in modules such as `'fs'`, `'events'`, or `'http'` or Node.js-specific functions such as `setTimeout()` or `setInterval()`. On the other hand, modules that depend on such Node.js builtins cannot be loaded in a GraalVM polyglot `Context`. -Supported NPM packages can be used in a GraalVM JavaScript `Context` using one of the following approaches: +Supported NPM packages can be used in a JavaScript `Context` using one of the following approaches: 1. Using a package bundler. For example, to combine multiple NPM packages in a single JavaScript [Source file](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Source.html). -2. Using ES modules on the local FileSystem. +2. Using ECMAScript (ES) modules on the local FileSystem. Optionally, a custom [Truffle FileSystem](https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/io/FileSystem.html) can be used to configure how files are resolved. -By default, a Java `Context` does not support loading modules using the CommonJS `require()` function. +By default, a Java `Context` does not load modules using the CommonJS `require()` function. This is because `require()` is a Node.js built-in function, and is not part of the ECMAScript specification. Experimental support for CommonJS modules can be enabled through the `js.commonjs-require` option as described below. ### ECMAScript Modules (ESM) -GraalVM JavaScript supports the full ES modules specification, including `import` statements, dynamic import of modules using `import()`, and advanced features such as [top-level `await`](https://github.com/tc39/proposal-top-level-await). -ECMAScript modules can be loaded in a `Context` simply by evaluating the module sources. -GraalVM JavaScript loads ECMAScript modules based on their file extension. -Therefore, any ECMAScript module should have file name extension `.mjs`. -Alternatively, the module [Source](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Source.html) should have Mime type `"application/javascript+module"`. +GraalJS supports the full ES modules specification, including `import` statements, dynamic modules import using `import()`, and advanced features such as [top-level `await`](https://github.com/tc39/proposal-top-level-await). + +ECMAScript modules can be loaded in a `Context` simply by evaluating the module sources. +GraalJS loads ECMAScript modules based on their file extension. +Therefore, any ECMAScript module should have file name extension _.mjs_. +Alternatively, the module [Source](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Source.html) should have MIME type `"application/javascript+module"`. -As an example, let's assume that you have a file named `foo.mjs` containing the following simple ES module: +As an example, let's assume that you have a file named _foo.mjs_ containing the following simple ES module: ```js export class Foo { @@ -49,7 +45,7 @@ export class Foo { } ``` -The ES module can be loaded in a polyglot `Context` in the following way: +This ES module can be loaded in a polyglot `Context` in the following way: ```java public static void main(String[] args) throws IOException { @@ -65,15 +61,14 @@ public static void main(String[] args) throws IOException { } ``` -Note that the ES module file has `.mjs` extension. +Note that the ES module file has _.mjs_ extension. Also note that the `allowIO()` option is provided to enable IO access. More examples of ES modules usage are available [here](https://github.com/oracle/graaljs/blob/master/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ESModuleTest.java). #### Module namespace exports -The `--js.esm-eval-returns-exports` option (off by default) can be used to expose the ES module namespace exported object to a Polyglot `Context`. +The `--js.esm-eval-returns-exports` option (false by default) can be used to expose the ES module namespace exported object to a Polyglot `Context`. This can be handy when an ES module is used directly from Java: - ```java public static void main(String[] args) throws IOException { @@ -96,10 +91,9 @@ public static void main(String[] args) throws IOException { ### Truffle FileSystem -By default, GraalVM JavaScript uses the built-in FileSystem of the polyglot `Context` to load and resolve ES modules. +By default, GraalJS uses the built-in FileSystem of the polyglot `Context` to load and resolve ES modules. A [FileSystem](https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/io/FileSystem.html) can be used to customize the ES modules loading process. For example, a custom FileSystem can be used to resolve ES modules using URLs: - ```java Context cx = Context.newBuilder("js").fileSystem(new FileSystem() { @@ -143,25 +137,25 @@ In this simple example, a custom FileSystem is used to load a dynamically-genera A complete example of a custom Truffle FileSystem to load ES modules can be found [here](https://github.com/oracle/graaljs/blob/master/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/ImportWithCustomFsTest.java). -### CommonJS Modules (CJS) +### CommonJS Modules By default, the `Context` API does not support CommonJS modules, and has no built-in `require()` function. In order to be loaded and used from a `Context` in Java, a CommonJS module needs to be _bundled_ into a self-contained JavaScript source file. -This can be done using one of the many popular open-source bundling tools such as Parcel, Browserify, and Webpack. +This can be achieved using one of the many popular open-source bundling tools such as Parcel, Browserify, and Webpack. Experimental support for CommonJS modules can be enabled through the `js.commonjs-require` option as described below. #### Experimental support for CommonJS NPM modules in the `Context` API The `js.commonjs-require` option provides a built-in `require()` function that can be used to load NPM-compatible CommonJS modules in a JavaScript `Context`. -Currently, this is an experimental feature not for production usage. +Currently, this is an experimental feature and not for production usage. To enable CommonJS support, a JavaScript context can be created in the following way: ```java Map options = new HashMap<>(); // Enable CommonJS experimental support. options.put("js.commonjs-require", "true"); -// (optional) folder where the NPM modules to be loaded are located. -options.put("js.commonjs-require-cwd", "/path/to/root/folder"); +// (optional) directory where the NPM modules to be loaded are located. +options.put("js.commonjs-require-cwd", "/path/to/root/directory"); // (optional) Node.js built-in replacements as a comma separated list. options.put("js.commonjs-core-modules-replacements", "buffer:buffer/," + @@ -177,34 +171,33 @@ Value module = cx.eval("js", "require('some-module');"); ``` The `"js.commonjs-require-cwd"` option can be used to specify the main folder where NPM packages have been installed. -As an example, this can be the folder where the `npm install` command was executed, or the folder containing your main `node_modules` folder. -Any NPM module will be resolved relative to that folder, including any built-in replacement specified using `"js.commonjs-core-modules-replacements"`. +As an example, this can be the directory where the `npm install` command was executed, or the directory containing your main _node\_modules/_ directory. +Any NPM module will be resolved relative to that directory, including any built-in replacement specified using `"js.commonjs-core-modules-replacements"`. ##### Differences with Node.js built-in `require()` function The `Context` built-in `require()` function can load regular NPM modules implemented in JavaScript, but cannot load native NPM modules. The built-in `require()` relies on the [FileSystem](https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/io/FileSystem.html), therefore I/O access needs to be enabled at context creation time using the [`allowIO` option](https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/Context.Builder.html#allowIO-boolean-). -The built-in `require()` aims to be largely compatible with Node.js, and we expect it to work with any NPM module that would work in a browser (e.g., created using a package bundler). +The built-in `require()` aims to be largely compatible with Node.js, and we expect it to work with any NPM module that would work in a browser (for example, created using a package bundler). ##### Installing an NPM module to be used via the `Context` API -In order to be used from a JavaScript `Context`, an NPM module needs to be installed to a local folder. -This can be done using GraalVM JavaScript's `npm install` command like one would normally do for Node.js applications. -At runtime, the option `js.commonjs-require-cwd` can be used to specify the main installation folder for NPM packages. -The `require()` built-in function will resolve packages according to the default Node.js' [package resolution protocol](https://nodejs.org/api/modules.html#modules_all_together) starting from the directory specified via `js.commonjs-require-cwd`. +To be used from a JavaScript `Context`, an NPM module needs to be installed to a local directory, for example, by running the `npm install` command. +At runtime, the option `js.commonjs-require-cwd` can be used to specify the main installation directory for NPM packages. +The `require()` built-in function resolves packages according to the default Node.js' [package resolution protocol](https://nodejs.org/api/modules.html#modules_all_together) starting from the directory specified via `js.commonjs-require-cwd`. When no directory is provided with the option, the current working directory of the application will be used. ##### Node.js core modules mockups -Some JavaScript applications or NPM modules might need functionalities that are available in Node.js' built-in modules (e.g., `'fs'` and `'buffer'`, etc.). +Some JavaScript applications or NPM modules might need functionalities that are available in Node.js' built-in modules (for example, `'fs'` and `'buffer'`). Such modules are not available in the `Context` API. -Thankfully, the Node.js community has developed high-quality JavaScript implementations for many Node.js core modules (e.g., the ['buffer'](https://www.npmjs.com/package/buffer) module for the browser). +Thankfully, the Node.js community has developed high-quality JavaScript implementations for many Node.js core modules (for example, the ['buffer'](https://www.npmjs.com/package/buffer) module for the browser). Such alternative module implementations can be exposed to a JavaScript `Context` using the `js.commonjs-core-modules-replacements` option, in the following way: ```java options.put("js.commonjs-core-modules-replacements", "buffer:my-buffer-implementation"); ``` -As the code suggests, the option instructs the GraalVM JavaScript runtime to load a module called `my-buffer-implementation` when an application attempts to load the Node.js `'buffer'` built-in module using `require('buffer')`. +As the code suggests, the option instructs GraalJS to load a module called `my-buffer-implementation` when an application attempts to load the Node.js `buffer` built-in module using `require('buffer')`. ##### Global symbols pre-initialization @@ -219,3 +212,7 @@ globalThis.Buffer = require('some-buffer-implementation').Buffer; // import another module that might use 'Buffer' require('another-module'); ``` + +### Related Documentation + +* [GraalJS Compatibility](JavaScriptCompatibility.md) \ No newline at end of file diff --git a/docs/user/Multithreading.md b/docs/user/Multithreading.md index 1146fd7f542..6fc49ed4c04 100644 --- a/docs/user/Multithreading.md +++ b/docs/user/Multithreading.md @@ -4,6 +4,7 @@ toc_group: js link_title: Multithreading permalink: /reference-manual/js/Multithreading/ --- + # Multithreading Running JavaScript on GraalVM supports multithreading. @@ -12,8 +13,7 @@ Depending on the usage scenario, threads can be used to execute parallel JavaScr ## Multithreading with Java and JavaScript Multithreading is supported when running JavaScript in the context of Java interoperability. -The basic model of multi-threaded execution supported by GraalVM is a "share-nothing" model that should be familiar to any JavaScript developer: - +The basic model of multithreaded execution supported by GraalVM is a "share-nothing" model that should be familiar to any JavaScript developer: 1. An arbitrary number of JavaScript `Context`s can be created, but they should be used by one thread at a time. 2. Concurrent access to JavaScript objects is not allowed: any JavaScript object cannot be accessed by more than one thread at a time. 3. Concurrent access to Java objects is allowed: any Java object can be accessed by any Java or JavaScript thread, concurrently. @@ -22,27 +22,14 @@ A JavaScript `Context` cannot be accessed by two or more threads, concurrently, ### Examples -The GraalVM JavaScript [unit tests](https://github.com/graalvm/graaljs/tree/master/graal-js/src/com.oracle.truffle.js.test.threading/src/com/oracle/truffle/js/test/threading) contain several examples of multi-threaded Java/JavaScript interactions. +The GraalJS [unit tests](https://github.com/graalvm/graaljs/tree/master/graal-js/src/com.oracle.truffle.js.test.threading/src/com/oracle/truffle/js/test/threading) contain several examples of multithreaded Java/JavaScript interactions. The most notable ones describe how: - 1. [Multiple `Context` objects can be executed in multiple threads](https://github.com/graalvm/graaljs/blob/master/graal-js/src/com.oracle.truffle.js.test.threading/src/com/oracle/truffle/js/test/threading/ConcurrentAccess.java). 2. [JavaScript values created by one thread can be used from another thread when proper synchronization is used](https://github.com/graalvm/graaljs/blob/master/graal-js/src/com.oracle.truffle.js.test.threading/src/com/oracle/truffle/js/test/threading/SingleThreadAccess.java). 3. [A `Context` can be accessed from multiple threads when proper synchronization is used](https://github.com/graalvm/graaljs/blob/master/graal-js/src/com.oracle.truffle.js.test.threading/src/com/oracle/truffle/js/test/threading/ConcurrentAccess.java). 4. [Java concurrency can be used from JavaScript](https://github.com/graalvm/graaljs/blob/master/graal-js/src/com.oracle.truffle.js.test.threading/src/com/oracle/truffle/js/test/threading/ForkJoinTest.java). 5. [Java objects can be accessed by multiple JavaScript threads, concurrently](https://github.com/graalvm/graaljs/blob/master/graal-js/src/com.oracle.truffle.js.test.threading/src/com/oracle/truffle/js/test/threading/SharedJavaObjects.java). -## Multithreading with Node.js - -The basic multithreading model of GraalVM JavaScript applies to Node.js applications as well. -In Node.js, a [Worker](https://nodejs.org/api/worker_threads.html#worker_threads_worker_threads) thread can be created to execute JavaScript code in parallel, but JavaScript objects cannot be shared between Workers. -On the contrary, a Java object created with GraalVM Java interoperability (e.g., using `Java.type()`) can be shared between Node.js Workers. -This allows multi-threaded Node.js applications to share Java objects. - -### Examples - -The GraalVM Node.js [unit tests](https://github.com/graalvm/graaljs/tree/master/graal-nodejs/test/graal/unit) contain several examples of multi-threaded Node.js applications. -The most notable examples show how: +### Related Documentation -1. [Node.js worker threads can execute Java code](https://github.com/graalvm/graaljs/blob/master/graal-nodejs/test/graal/unit/worker.js). -2. [Java objects can be shared between Node.js worker threads](https://github.com/graalvm/graaljs/blob/master/graal-nodejs/test/graal/unit/javaMessages.js). -3. [JavaScript `Promise` objects can be used to `await` on messages from workers, using Java objects to bind promises to worker messages](https://github.com/graalvm/graaljs/blob/master/graal-nodejs/test/graal/unit/workerInteropPromises.js). +* [Java Interoperability](JavaInteroperability.md) \ No newline at end of file diff --git a/docs/user/NashornMigrationGuide.md b/docs/user/NashornMigrationGuide.md index 3fa5de93ab4..56b513ad319 100644 --- a/docs/user/NashornMigrationGuide.md +++ b/docs/user/NashornMigrationGuide.md @@ -1,23 +1,23 @@ --- layout: docs toc_group: js -link_title: Migration Guide from Nashorn to GraalVM JavaScript +link_title: Migration Guide from Nashorn to GraalJS permalink: /reference-manual/js/NashornMigrationGuide/ --- -# Migration Guide from Nashorn to GraalVM JavaScript + +# Migration Guide from Nashorn to GraalJS This guide serves as a migration guide for code previously targeted to the Nashorn engine. -See the [Java Interoperability](JavaInteroperability.md) guide for an overview of supported Java interoperability features. +See the [Java Interoperability guide](JavaInteroperability.md) for an overview of supported Java interoperability features. -The Nashorn engine has been deprecated in JDK 11 as part of [JEP 335](https://openjdk.java.net/jeps/335) and -and has been removed from JDK15 as part of [JEP 372](https://openjdk.java.net/jeps/372). +The Nashorn engine has been deprecated in JDK 11 as part of [JEP 335](https://openjdk.java.net/jeps/335) and has been removed from JDK15 as part of [JEP 372](https://openjdk.java.net/jeps/372). -GraalVM can step in as a replacement for JavaScript code previously executed on the Nashorn engine. -GraalVM provides all the features for JavaScript previously provided by Nashorn. -Many are available by default, some are behind flags, and others require minor modifications to your source code. +GraalJS can step in as a replacement for JavaScript code previously executed on the Nashorn engine. +GraalJS provides all the features for JavaScript previously provided by Nashorn. +Many are available by default, some are behind options, and others require minor modifications to your source code. -Both Nashorn and GraalVM JavaScript support a similar set of syntax and semantics for Java interoperability. -One notable difference is that GraalVM JavaScript takes a _secure by default_ approach, meaning some features need to be explicitly enabled that were available by default on Nashorn. +Both Nashorn and GraalJS support a similar set of syntax and semantics for Java interoperability. +One notable difference is that GraalJS takes a _secure by default_ approach, meaning some features need to be explicitly enabled that were available by default on Nashorn. The most important differences relevant for migration are listed here. Nashorn features available by default (dependent on [security settings](#secure-by-default)): @@ -28,38 +28,39 @@ Nashorn features available by default (dependent on [security settings](#secure- ## Nashorn Compatibility Mode -GraalVM JavaScript provides a Nashorn compatibility mode. +GraalJS provides a Nashorn compatibility mode. Some of the functionality necessary for Nashorn compatibility is only available when the `js.nashorn-compat` option is enabled. -This is the case for Nashorn-specific extensions that GraalVM JavaScript does not want to expose by default. +This is the case for Nashorn-specific extensions that GraalJS does not want to expose by default. -Note that you have to enable [experimental options](Options.md#stable-and-experimental-options) to use this flag. -Further note that setting this flag defeats the [secure by default](#secure-by-default) approach of GraalVM JavaScript in some cases, e.g., when operating on a legacy `ScriptEngine`. +Note that you have to unlock [experimental features](Options.md#stable-and-experimental-options) to use this option. +Further note that setting this option defeats the [secure by default](#secure-by-default) approach of GraalJS in some cases, for example, when operating on a legacy `ScriptEngine`. When you use the Nashorn compatibility mode, by default, ECMAScript 5 is set as compatibility level. -You can specify a different ECMAScript version using the `js.ecmascript-version` flag; note that this might conflict with full Nashorn compatibilty. -A code example how to set the flag is given near the end of this section. +You can specify a different ECMAScript version using the `js.ecmascript-version` option. +Note that this might conflict with full Nashorn compatibility. +A code example how to set the option is given near the end of this section. The `js.nashorn-compat` option can be set: -1. by using a command line option: -```shell -js --experimental-options --js.nashorn-compat=true -``` - -2. by using the Polyglot API: -```java -import org.graalvm.polyglot.Context; - -try (Context context = Context.newBuilder().allowExperimentalOptions(true).option("js.nashorn-compat", "true").build()) { - context.eval("js", "print(__LINE__)"); -} -``` - -3. by using a system property when starting a Java application (remember to enable `allowExperimentalOptions` on the `Context.Builder` in your application as well): -```shell -java -Dpolyglot.js.nashorn-compat=true MyApplication -``` - -Functionality only available under the `nashorn-compat` flag includes: +- By using a command line option: + ```shell + js --experimental-options --js.nashorn-compat=true + ``` + +- By using the Polyglot API: + ```java + import org.graalvm.polyglot.Context; + + try (Context context = Context.newBuilder().allowExperimentalOptions(true).option("js.nashorn-compat", "true").build()) { + context.eval("js", "print(__LINE__)"); + } + ``` + +- By using a system property when starting a Java application (remember to enable `allowExperimentalOptions` on the `Context.Builder` in your application as well): + ```shell + java -Dpolyglot.js.nashorn-compat=true MyApplication + ``` + +Functionality only available under the `nashorn-compat` option includes: * `Java.isJavaFunction`, `Java.isJavaMethod`, `Java.isScriptObject`, `Java.isScriptFunction` * `new Interface|AbstractClass(fn|obj)` * `JavaImporter` @@ -69,8 +70,7 @@ Functionality only available under the `nashorn-compat` flag includes: * `exit`, `quit` The `js.ecmascript-version` option can be set in similar fashion. -As this is a supported option, there is no need to provide the `experimental-options` flag just for setting the `ecmascript-version`: -1. by using a command line option: +As this is a supported option, there is no need to provide the `experimental-options` option just for setting the `ecmascript-version`: ```shell js --js.ecmascript-version=2020 ``` @@ -80,48 +80,54 @@ js --js.ecmascript-version=2020 [Nashorn syntax extensions](https://wiki.openjdk.java.net/display/Nashorn/Nashorn+extensions) can be enabled using the `js.syntax-extensions` experimental option. They are also enabled by default in the Nashorn compatibility mode (`js.nashorn-compat`). -## GraalVM JavaScript vs Nashorn +## GraalJS vs Nashorn -GraalVM JavaScript differs from Nashorn in some aspects that were intentional design decisions. +GraalJS differs from Nashorn in some aspects that were intentional design decisions. ### Secure by Default -GraalVM JavaScript takes a _secure by default_ approach. + +GraalJS takes a _secure by default_ approach. Unless explicitly permitted by the embedder, JavaScript code cannot access Java classes or access the file system, among other restrictions. -Several features of GraalVM JavaScript, including Nashorn compatibility features, are only available when the relevant security settings are permissive enough. +Several features of GraalJS, including Nashorn compatibility features, are only available when the relevant security settings are permissive enough. + Make sure you [understand the security implications](https://github.com/oracle/graal/blob/master/docs/security/security-guide.md) of any change that lifts the secure default limits to your application and the host system. For a full list of available settings, see [`Context.Builder`](https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/Context.Builder.html). -Those flags can be defined when building the context with GraalVM Polyglot API. +Those options can be defined when building the context with the Polyglot API. -Flags frequently required to enable features of GraalVM JavaScript are: -* `allowHostAccess()`: configure which public constructors, methods or fields of public classes are accessible by guest applications. Use `HostAccess.EXPLICIT` or a custom `HostAccess` policy to selectively enable access. Set to `HostAccess.ALL` to allow unrestricted access. -* `allowHostClassLookup()`: set a filter that specifies the Java host classes that can be looked up by the guest application. Set to the Predicate `className -> true` to allow lookup of all classes. -* `allowIO()`: allow the guest language to perform unrestricted IO operations on the host system, required, e.g., to `load()` from the file system. Set to `true` to enable IO. +Options frequently required to enable features of GraalJS are: +* `allowHostAccess()`: configure which public constructors, methods or fields of public classes are accessible by a guest application. Use `HostAccess.EXPLICIT` or a custom `HostAccess` policy to selectively enable access. Set to `HostAccess.ALL` to allow unrestricted access. +* `allowHostClassLookup()`: set a filter that specifies the Java host classes that can be looked up by a guest application. Set to the Predicate `className -> true` to allow lookup of all classes. +* `allowIO()`: allow a guest language to perform unrestricted IO operations on the host system, required, for example, to `load()` from the file system. Set to `true` to enable IO. -If you run code on the legacy `ScriptEngine`, see [Setting options via `Bindings`](https://github.com/graalvm/graaljs/blob/master/docs/user/ScriptEngine.md#setting-options-via-bindings) regarding how to set them there. +If you run code on the legacy `ScriptEngine`, see [Setting Options via `Bindings`](ScriptEngine.md#setting-options-via-bindings) regarding how to set them there. -Finally, note that the `nashorn-compat` mode enables the relevant flags when executing code on the `ScriptEngine` (but not on `Context`), to provide better compatibilty with Nashorn in that setup. +Finally, note that the `nashorn-compat` mode enables the relevant options when executing code on the `ScriptEngine` (but not on `Context`), to provide better compatibility with Nashorn in that setup. ### Launcher Name `js` -GraalVM JavaScript comes with a binary launcher named `js`. -Note that, depending on the build setup, GraalVM might still ship Nashorn and its `jjs` launcher. + +GraalJS comes with a binary launcher named `js`. +Note that, depending on the build environment, GraalJS might still ship Nashorn and its `jjs` launcher. ### ScriptEngine Name `graal.js` -GraalVM JavaScript is shipped with support for `ScriptEngine`. + +GraalJS is shipped with support for `ScriptEngine`. It registers under several names, including "graal.js", "JavaScript", and "js". Be sure to activate the Nashorn compatibility mode as described above if you need full Nashorn compatibility. -Depending on the build setup, GraalVM might still ship Nashorn and provide it via ScriptEngine. +Depending on the build setup, GraalJS might still ship Nashorn and provide it via `ScriptEngine`. For more details, see [ScriptEngine Implementation](ScriptEngine.md). ### `ClassFilter` -GraalVM JavaScript supports a class filter when starting with a polyglot `Context`. + +GraalJS provides a class filter when starting with a polyglot `Context`. See [`Context.Builder.hostClassFilter`](http://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.Builder.html#hostClassFilter-java.util.function.Predicate-). ### Fully Qualified Names -GraalVM Javascript requires the use of `Java.type(typename)`. -It does not support accessing classes just by their fully qualified class name by default. + +GraalJS requires the use of `Java.type(typename)`. +It does not support accessing classes just by their fully qualified class name by default. `Java.type` brings more clarity and avoids the accidental use of Java classes in JavaScript code. -For instance, look at this pattern: +For example, look at this pattern: ```js var bd = new java.math.BigDecimal('10'); ``` @@ -133,17 +139,20 @@ var bd = new BigDecimal('10'); ``` ### Lossy Conversion -GraalVM JavaScript does not allow lossy conversions of arguments when calling Java methods. + +GraalJS does not allow lossy conversions of arguments when calling Java methods. This could lead to bugs with numeric values that are hard to detect. -GraalVM JavaScript will always select the overloaded method with the narrowest possible argument types that can be converted to without loss. -If no such overloaded method is available, GraalVM JavaScript throws a `TypeError` instead of lossy conversion. +GraalJS always selects the overloaded method with the narrowest possible argument types that can be converted to without loss. +If no such overloaded method is available, GraalJS throws a `TypeError` instead of lossy conversion. In general, this affects which overloaded method is executed. -Custom `targetTypeMapping`s can be used to customize behaviour. See [HostAccess.Builder#targetTypeMapping](https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/HostAccess.Builder.html#targetTypeMapping-java.lang.Class-java.lang.Class-java.util.function.Predicate-java.util.function.Function-). +Custom `targetTypeMapping`s can be used to customize behavior. +See [HostAccess.Builder#targetTypeMapping](https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/HostAccess.Builder.html#targetTypeMapping-java.lang.Class-java.lang.Class-java.util.function.Predicate-java.util.function.Function). ### `ScriptObjectMirror` Objects -GraalVM JavaScript does not provide objects of the class `ScriptObjectMirror`. + +GraalJS does not provide objects of the class `ScriptObjectMirror`. Instead, JavaScript objects are exposed to Java code as objects implementing Java's `Map` interface. Code referencing `ScriptObjectMirror` instances can be rewritten by changing the type to either an interface (`Map` or `List`) or the polyglot [Value](http://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Value.html) class which provides similar capabilities. @@ -156,12 +165,12 @@ Multiple JavaScript engines can be created from a Java application, and can be s ```js Context polyglot = Context.create(); Value array = polyglot.eval("js", "[1,2,42,4]"); - ``` -GraalVM JavaScript does not allow the creation of threads from JavaScript applications with access to the current `Context`. -Moreover, GraalVM JavaScript does not allow concurrent threads to access the same `Context` at the same time. -This could lead to unmanagable synchronization problems like data races in a language that is not prepared for multithreading. For example: +GraalJS does not allow the creation of threads from JavaScript with access to the current `Context`. +Moreover, GraalJS does not allow concurrent threads to access the same `Context` at the same time. +This could lead to unmanageable synchronization problems like data races in a language that is not prepared for multithreading. +For example: ```js new Thread(function() { print('printed from another thread'); // throws Exception due to potential synchronization problems @@ -173,46 +182,52 @@ The child thread may not access the `Context` of the parent thread or of any oth In case of violations, an `IllegalStateException` will be thrown. A child thread may create a new `Context` instance, though. ```js -new Thread(aJavaRunnable).start(); // allowed on GraalVM JavaScript +new Thread(aJavaRunnable).start(); // allowed on GraalJS ``` -With proper synchronization in place, multiple contexts can be shared between different threads. The example Java applications using GraalVM JavaScript `Context`s from multiple threads can be found [here](https://github.com/graalvm/graaljs/tree/master/graal-js/src/com.oracle.truffle.js.test.threading/src/com/oracle/truffle/js/test/threading). +With proper synchronization in place, multiple contexts can be shared between different threads. +The example Java applications using JavaScript `Context`s from multiple threads can be found [here](https://github.com/graalvm/graaljs/tree/master/graal-js/src/com.oracle.truffle.js.test.threading/src/com/oracle/truffle/js/test/threading). ## Extensions Only Available in Nashorn Compatibility Mode -The following extensions to JavaScript available in Nashorn are deactivated in GraalVM JavaScript by default. -They are provided in GraalVM's Nashorn compatibility mode. +The following JavaScript extensions available in Nashorn are deactivated in GraalJS by default. +They are provided in the Nashorn compatibility mode. It is highly recommended not to implement new applications based on those features, but only to use it as a means to migrate existing applications to GraalVM. ### String `length` Property -GraalVM JavaScript does not treat the length property of a String specially. + +GraalJS does not treat the length property of a String specially. The canonical way of accessing the String length is reading the `length` property: ```js myJavaString.length; ``` -Nashorn allows users to access `length` as both a property and a function. +Nashorn enables users to access `length` as both a property and a function. Existing function calls `length()` should be expressed as property access. Nashorn behavior is mimicked in the Nashorn compatibility mode. ### Java Packages in the JavaScript Global Object -GraalVM JavaScript requires the use of `Java.type` instead of fully qualified names. + +GraalJS requires the use of `Java.type` instead of fully qualified names. In the Nashorn compatibility mode, the following Java packages are added to the JavaScript global object: `java`, `javafx`, `javax`, `com`, `org`, and `edu`. ### JavaImporter + The `JavaImporter` feature is available only in the Nashorn compatibility mode. ### JSAdapter + The use of the non-standard `JSAdapter` feature is discouraged and should be replaced with the equivalent standard `Proxy` feature. For compatibility, `JSAdapter` is still available in the Nashorn compatibility mode. ### Java.* Methods -Several methods provided by Nashorn on the `Java` global object are available only in the Nashorn compatibility mode, or currently not supported by GraalVM JavaScript. + +Several methods provided by Nashorn on the `Java` global object are available only in the Nashorn compatibility mode, or currently not supported by GraalJS. Available in the Nashorn compatibility mode are: `Java.isJavaFunction`, `Java.isJavaMethod`, `Java.isScriptObject`, and `Java.isScriptFunction`. `Java.asJSONCompatible` is currently not supported. ### Accessors -In the Nashorn compatibility mode, GraalVM JavaScript allows users to access getters and setters just by using the names as properties, while omitting `get`, `set`, or `is`: +In the Nashorn compatibility mode, GraalJS allows users to access getters and setters just by using the names as properties, while omitting `get`, `set`, or `is`: ```js var Date = Java.type('java.util.Date'); var date = new Date(); @@ -221,23 +236,30 @@ var myYear = date.year; // calls date.getYear() date.year = myYear + 1; // calls date.setYear(myYear + 1); ``` -GraalVM JavaScript mimics the behavior of Nashorn regarding the ordering of the access: -* In case of a read operation, GraalVM JavaScript will first try to call a getter with the name `get` and the property name in camel case. If that is not available, a getter with the name `is` and the property name in camel case is called. In the second case, unlike Nashorn, the resulting value is returned even if it is not of type boolean. Only if both methods are not available, the property itself will be read. -* In case of a write operation, GraalVM JavaScript will try to call a setter with the name `set` and the property name in camel case, providing the value as argument to that function. If the setter is not available, the property itself will be written. +GraalJS mimics the behavior of Nashorn regarding the ordering of the access: +* In case of a read operation, GraalJS will first try to call a getter with the name `get` and the property name in camel case. If that is not available, a getter with the name `is` and the property name in camel case is called. In the second case, unlike Nashorn, the resulting value is returned even if it is not of type boolean. Only if both methods are not available, the property itself will be read. +* In case of a write operation, GraalJS will try to call a setter with the name `set` and the property name in camel case, providing the value as argument to that function. If the setter is not available, the property itself will be written. -Note that Nashorn (and thus, GraalVM JavaScript) makes a clear distinction between property read/writes and function calls. +Note that Nashorn (and thus, GraalJS) makes a clear distinction between property read/writes and function calls. When the Java class has both a field and a method of the same name publicly available, `obj.property` will always read the field (or the getter as discussed above), while `obj.property()` will always call the respective method. ## Additional Aspects to Consider -### Features of GraalVM JavaScript -GraalVM JavaScript supports features of the newest ECMAScript specification and some extensions to it. +### Features of GraalJS + +GraalJS supports features of the newest ECMAScript specification and some extensions to it. See [JavaScript Compatibility](JavaScriptCompatibility.md). Note that this example adds objects to the global scope that might interfere with existing source code unaware of those extensions. ### Console Output -GraalVM JavaScript provides a `print` builtin function compatible with Nashorn. -Note that GraalVM JavaScript also provides a `console.log` function. +GraalJS provides a `print` builtin function compatible with Nashorn. + +Note that GraalJS also provides a `console.log` function. This is an alias for `print` in pure JavaScript mode, but uses an implementation provided by Node.js when running in Node mode. -The behaviour around Java objects differs for `console.log` in Node mode as Node.js does not implement special treatment for such objects. +The behavior around Java objects differs for `console.log` in Node mode as Node.js does not implement special treatment for such objects. + +### Related Documentation + +* [Migration Guide from Rhino to GraalJS](RhinoMigrationGuide.md) +* [Java Interoperability](JavaInteroperability.md) \ No newline at end of file diff --git a/docs/user/NodeJS.md b/docs/user/NodeJS.md index 4da23c2c6bd..520d369d919 100644 --- a/docs/user/NodeJS.md +++ b/docs/user/NodeJS.md @@ -4,22 +4,27 @@ toc_group: js link_title: Node.js Runtime permalink: /reference-manual/js/NodeJS/ --- + # Node.js Runtime -GraalVM can run unmodified Node.js applications. +GraalVM can run unmodified Node.js applications. +GraalVM's Node.js runtime is based on a recent version of Node.js, and runs the GraalVM JavaScript engine (GraalJS) instead of Google V8. +Some internal features (for example, VM-internal statistics, configuration, profiling, debugging, and so on) are unsupported, or supported with potentially different behavior. + Applications can freely import and use NPM packages, including native ones. +## Getting Started with Node.js + +As of GraalVM for JDK 21, the GraalVM Node.js runtime is available as a separate distribution. +Two standalone runtime options are available for both Oracle GraalVM and GraalVM Community Edition: a Native Image compiled launcher or a JVM-based runtime. +To distinguish between them, the GraalVM Community Edition version has the suffix `-community` in the name: `graaljs-community---.tar.gz`, `graalnodejs-community---.tar.gz`. +A standalone that comes with a JVM has a `-jvm` suffix in a name. + To enable the GraalVM Node.js runtime, install the Node.js distribution based on Oracle GraalVM or GraalVM Community Edition for your operating system. -1. Navigate to [GitHub releases](https://github.com/oracle/graaljs/releases/) and download Node.js. +1. Navigate to [GitHub releases](https://github.com/oracle/graaljs/releases/) and select a desired standalone for your operating system. 2. Unzip the archive: - - > Note: If you are using macOS Catalina and later, first remove the quarantine attribute: - ```shell - sudo xattr -r -d com.apple.quarantine .tar.gz - ``` - Unzip: ```shell tar -xzf .tar.gz ``` @@ -30,24 +35,46 @@ To enable the GraalVM Node.js runtime, install the Node.js distribution based on ./path/to/bin/node --version ``` -The Node.js standalone provides `node` and `npm` launchers. -The `npm` command is equivalent to the default Node.js command and supports all Node.js APIs. - -For the differences between running the `node` native launcher and accessing Node.js NPM modules or ECMAScript modules from a Java Context, see [NodeJSVSJavaScriptContext](NodeJSVSJavaScriptContext.md). - ## Running Node.js Applications -To run a Node.js-based application, use the `node` launcher: +The Node.js installation provides `node` and `npm` launchers: ```shell node [options] [filename] [args] ``` -GraalVM's Node.js runtime is based on a recent version of Node.js, and runs the GraalVM JavaScript engine instead of Google V8. -Thus, some internal features (e.g., VM-internal statistics, configuration, profiling, debugging, etc.) are unsupported, or supported with potentially different behavior. - -The `node` command is largely compatible with Node.js, and features additional GraalVM-specific functionalities (e.g., interoperability with Java and all other GraalVM languages). +The `npm` command is equivalent to the default Node.js command, and features additional GraalVM-specific functionalities (for example, interoperability with Java). A list of available options can be obtained with `node --help`. +Use the `node` launcher to execute a Node.js application. For example: + +1. Install the `colors` and `ansispan` packages using `npm install` as follows: + ```shell + npm install colors ansispan + ``` + After the packages are installed, you can use them from your application. + +2. Add the following code snippet to a file named _app.js_ and save it in the same directory where you installed the Node.js packages: + ```js + const http = require("http"); + const span = require("ansispan"); + require("colors"); + + http.createServer(function (request, response) { + response.writeHead(200, {"Content-Type": "text/html"}); + response.end(span("Hello Node.js!".green)); + }).listen(8000, function() { console.log("Node.js server running at http://127.0.0.1:8000/".red); }); + + setTimeout(function() { console.log("DONE!"); process.exit(); }, 2000); + ``` + +3. Execute it on the GraalVM Node.js runtime using the `node` command as follows: + ```shell + node app.js + ``` + +The Node.js functionality is available when an application is started from the `node` binary launcher. +Certain limits apply when launching a Node.js application or accessing NPM packages from a Java context, see [Node.js vs. Java Script Context](NodeJSVSJavaScriptContext.md). + ## Installing Packages Using `npm` To install a Node.js package, use the `npm` launcher. @@ -55,21 +82,129 @@ The `npm` command is equivalent to the default NPM command, and supports most of An NPM package can be installed with: ```shell -npm install +npm install [package] ``` -As the `npm` command of GraalVM Node.js is largely compatible with NPM, packages will be installed in the `node_modules` folder, as expected. +As the `npm` command of GraalVM Node.js is largely compatible with NPM, packages are installed in the _node\_modules/_ directory, as expected. -### Installing `npm` Packages Globally +## Installing `npm` Packages Globally Node packages can be installed globally using `npm` and the `-g` option. -By default, `npm` installs global packages (links to their executables) in the path where the `node` executable is installed, typically `NODE/bin`. -That folder is where global packages are installed. +By default, `npm` installs global packages (links to their executables) in the path where the `node` executable is installed, typically _node/bin/_. +That directory is where global packages are installed. You might want to add that directory to your `$PATH` if you regularly use globally installed packages, especially their command line interfaces. -Another option is to specify the global installation folder of `npm` by setting the `$PREFIX` environment variable, or by specifying the `--prefix` option when running `npm install`. -For example, the following command will install global packages in the `/foo/bar` folder: +Another option is to specify the global installation directory of `npm` by setting the `$PREFIX` environment variable, or by specifying the `--prefix` option when running `npm install`. +For example, the following command will install global packages in the _/foo/bar/_ directory: ```shell npm install --prefix /foo/bar -g ``` More details about `prefix` can be found in the [official NPM documentation](https://docs.npmjs.com/cli/prefix.html). + +## Interoperability with Java + +The Node.js runtime cannot be embedded into a JVM but has to be started as a separate process. + +1. Save the following code in a file named _HelloPolyglot.java_ and compile: + ```java + import org.graalvm.polyglot.*; + import org.graalvm.polyglot.proxy.*; + + public class HelloPolyglot { + + static String JS_CODE = "(function myFun(param){console.log('hello '+param);})"; + + public static void main(String[] args) { + System.out.println("Hello Java!"); + try (Context context = Context.create()) { + Value value = context.eval("js", JS_CODE); + value.execute(args[0]); + } + } + } + ``` + +2. Then save this code a file named _app.js_: + ```js + var HelloPolyglot = Java.type("HelloPolyglot"); + + HelloPolyglot.main(["from node.js"]); + + console.log("done"); + ``` + +3. Run it with `node`: + ```shell + node --vm.cp=. app.js + ``` + You should see the following output: + ``` + Hello Java! + hello from node.js + done + ``` + +Both Node.js and JVM then run in the same process and the interoperability works using the same `Value` classes as above. + +For the differences between running the `node` launcher and accessing Node.js NPM modules or ECMAScript modules from a Java `Context`, see [NodeJSVSJavaScriptContext](NodeJSVSJavaScriptContext.md). + +## Multithreading with Node.js + +The basic [multithreading model of GraalJS](Multithreading.md) applies to Node.js applications as well. +In Node.js, a [Worker](https://nodejs.org/api/worker_threads.html#worker_threads_worker_threads) thread can be created to execute JavaScript code in parallel, but JavaScript objects cannot be shared between Workers. +On the contrary, a Java object created with GraalVM Java interoperability (for example, using `Java.type()`) can be shared between Node.js Workers. +This allows multithreaded Node.js applications to share Java objects. + +The GraalVM Node.js [unit tests](https://github.com/graalvm/graaljs/tree/master/graal-nodejs/test/graal/unit) contain several examples of multithreaded Node.js applications. +The most notable examples show how: +1. [Node.js worker threads can execute Java code](https://github.com/graalvm/graaljs/blob/master/graal-nodejs/test/graal/unit/worker.js). +2. [Java objects can be shared between Node.js worker threads](https://github.com/graalvm/graaljs/blob/master/graal-nodejs/test/graal/unit/javaMessages.js). +3. [JavaScript `Promise` objects can be used to `await` on messages from workers, using Java objects to bind promises to worker messages](https://github.com/graalvm/graaljs/blob/master/graal-nodejs/test/graal/unit/workerInteropPromises.js). + +## Frequently Asked Questions + +### Is GraalVM's Node.js runtime compatible with the original Node implementation? +GraalVM's Node.js runtime is largely compatible with the original Node.js (based on the V8 engine). +This leads to a high number of `npm`-based modules being compatible. +In fact, out of the 100k `npm` modules we test, more than 94% of them pass all tests. +Still, several sources of differences have to be considered: + +- **Setup:** +GraalVM's Node.js mostly mimicks the original setup of Node, including the `node` executable, `npm`, and similar. +However, not all command-line options are supported (or behave exactly identically). +Modules might require that native modules are (re)compiled against the _v8.h_ file. + + As of GraalVM for JDK 21, the GraalVM Node.js runtime is available as a separate distribution. + See [Getting Started with Node.js](#getting-started-with-nodejs). + +- **Internals:** +GraalVM's Node.js is implemented on top of a JVM, and thus has a different internal architecture than Node.js based on V8. +This implies that some internal mechanisms behave differently and cannot exactly replicate V8 behavior. +This will hardly ever affect user code, but might affect modules implemented natively, depending on V8 internals. + +- **Performance:** +Due to GraalVM's Node.js being implemented on top of a JVM, performance characteristics vary from the original native implementation. +While GraalVM's peak performance can match V8 on many benchmarks, it will typically take longer to reach the peak (known as _warmup_). +Be sure to give the Graal compiler some extra time when measuring (peak) performance. + +- **Compatibility:** +GraalVM's Node.js runtime uses the following approaches to check and retain compatibility with Node.js code: + * node-compat-table: GraalVM's Node.js is compared against other engines using the _node-compat-table_ module, highlighting incompatibilities that might break Node.js code. + * automated mass-testing of modules using _mocha_: in order to test a large set of modules, GraalVM's Node.js runtime is tested against 95k modules that use the mocha test framework. Using mocha allows automating the process of executing the test and comprehending the test result. + * manual testing of popular modules: a select list of `npm` modules is tested in a manual test setup. These highly-relevant modules are tested in a more sophisticated manner. + +### Can NPM packages be installed globally? +Node packages can be installed globally using `npm` and the `-g` option, both with the GraalVM's Node.js implementation. + +While the original Node.js implementation has one main directory (_node/bin/_) to put binaries and globally installed packages and their command-line tools, GraalVM's Node.js puts binaries in the _/path/to/graaljs/bin/_ directory. +When installing NPM packages globally on the GraalVM Node.js runtime, links to the executables, for example, for command line interface tools are put to the JavaScript-specific directory. +In order for globally installed packages to function properly, you might need to add `/path/to/graaljs/bin` to your `$PATH`. + +Another option is to specify the global installation directory of `npm` by setting the `$PREFIX` environment variable, or by specifying the `--prefix` option when running `npm install`. + +For more details, see [Installing `npm` Packages Globally](NodeJS.md#installing-npm-packages-globally). + +### Related Documentation + +* [Differences Between `node` Native Launcher and a Java `Context`](NodeJSVSJavaScriptContext.md) + diff --git a/docs/user/NodeJSVSJavaScriptContext.md b/docs/user/NodeJSVSJavaScriptContext.md index 41b5f7b6d86..a5114d598f4 100644 --- a/docs/user/NodeJSVSJavaScriptContext.md +++ b/docs/user/NodeJSVSJavaScriptContext.md @@ -4,41 +4,41 @@ toc_group: js link_title: Differences Between Node.js and Java Embeddings permalink: /reference-manual/js/NodeJSvsJavaScriptContext/ --- + # Differences Between Node.js and Java Embeddings -GraalVM provides a fully-compliant ECMAScript 2023 JavaScript language runtime. +GraalVM provides a fully-compliant ECMAScript 2024 JavaScript runtime. As such, it can run JavaScript code in a variety of embedding scenarios, including [Oracle Database](https://medium.com/graalvm/mle-executing-javascript-in-oracle-database-c545feb1a010), any Java-based application, and Node.js. -Depending on the GraalVM's JavaScript embedding scenario, applications have access to different built-in capabilities. -For example, Node.js applications executed using GraalVM's `bin/node` executable have access to all of Node.js' APIs, including built-in Node.js modules such as `fs`, `http`, etc. +Depending on the embedding scenario, applications have access to different built-in capabilities. +For example, Node.js applications executed using GraalVM's `bin/node` executable have access to all of Node.js' APIs, including built-in Node.js modules such as `fs`, `http`, and so on. Conversely, JavaScript code embedded in a Java application has access to limited capabilities, as specified through the [Context API](https://github.com/oracle/graal/blob/master/docs/reference-manual/embedding/embed-languages.md#compile-and-run-a-polyglot-application), and do not have access to Node.js built-in modules. -This guide describes the main differences between a Node.js application and a GraalVM JavaScript application embedded in Java. +This guide describes the main differences between a Node.js application and JavaScript embedded in a Java application. ## Context Creation -JavaScript code in GraalVM can be executed using a GraalVM execution _Context_. +JavaScript code in GraalVM can be executed using an execution _context_. In a Java application, a new context can be created using the [`Context` API](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.html). -New contexts can be configured in multiple ways, and configuration options include exposing access to Java classes, allowing access to IO, etc. +New contexts can be configured in multiple ways, and configuration options include exposing access to Java classes, allowing access to IO, and so on. A list of context creation options can be found in the [API documentation](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.html). -In this scenario, Java classes can be exposed to JavaScript by using GraalVM's [polyglot `Bindings`](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.html#getPolyglotBindings--). +In this scenario, Java classes can be exposed to JavaScript by using GraalVM's [Polyglot `Bindings`](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.html#getPolyglotBindings). In a Node.js application, the GraalVM `Context` executing the application is pre-initialized by the Node.js runtime, and cannot be configured by the user application. In this scenario, Java classes can be exposed to the Node.js application by using the `--vm.cp=` command line option of the `bin/node` command, as described below. - ## Java Interoperability JavaScript applications can interact with Java classes using the `Java` built-in object. -This object is available by default in the `js` and `node` launchers, but accessing Java classes is only possible in the JVM standalones (that have `-jvm` in the name). +This object is available by default in the `js` and `node` launchers, but accessing Java classes is only possible in the JVM standalone (that have `-jvm` in the name). -When embedding GraalVM JavaScript using the Polyglot API, you have to explicitly enable host access in the [`Context.Builder`](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.Builder.html) (`allowHostAccess`, `allowHostClassLookup`). -More details on the Java interoperability capabilities of GraalVM JavaScript are available in [Java Interoperability](JavaInteroperability.md). +When embedding JavaScript using the Polyglot API, you have to explicitly enable host access in the [`Context.Builder`](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.Builder.html) (`allowHostAccess`, `allowHostClassLookup`). +More details on the JavaScript-Java interoperability are available in the [Java Interoperability guide](JavaInteroperability.md). ## Multithreading -A GraalVM context running JavaScript enforces a "share-nothing" model of parallelism: no JavaScript values can be accessed by two concurrent Java threads at the same time. +A polyglot `Context` running JavaScript enforces a "share-nothing" model of parallelism: no JavaScript values can be accessed by two concurrent Java threads at the same time. In order to leverage parallel execution, multiple contexts have to be created and executed from multiple threads: 1. In Node.js mode, multiple contexts can be created using Node.js' [Worker threads](https://nodejs.org/api/worker_threads.html) API. @@ -46,26 +46,31 @@ The Worker threads API ensures that no sharing can happen between two parallel c 2. In Java, multiple contexts can be executed from multiple threads. As long as a context is not accessed by two threads at the same time, parallel execution happens safely. -More details on parallel execution in GraalVM JavaScript are available in [this blog post](https://medium.com/graalvm/multi-threaded-java-javascript-language-interoperability-in-graalvm-2f19c1f9c37b). +More details on parallel execution in GraalJS are available in [this blog post](https://medium.com/graalvm/multi-threaded-java-javascript-language-interoperability-in-graalvm-2f19c1f9c37b). ## Java Libraries -Java libraries can be accessed from JavaScript in GraalVM through the `Java` built-in object. -In order for a Java library to be accessible from a `Context`, its `jar` files need to be added to the GraalVM classpath. This can be done in the following way: - -1. In Node.js mode, the classpath can be modified using the `--vm.cp` option. +Java libraries can be accessed from GraalJS through the `Java` built-in object. +In order for a Java library to be accessible from a `Context`, its JAR files need to be added to the class path. +This can be done in the following way: +1. In Node.js mode, the class path can be modified using the `--vm.cp` option. 2. In Java, the default Java's `-cp` option can be used. -More details on GraalVM command line options are available in [Options](Options.md). +Read more in [Command-line Options](Options.md). ## JavaScript Packages and Modules Many popular JavaScript modules such as those available on the `npm` package registry can be used from Node.js as well as from Java: 1. In Node.js mode, JavaScript modules are handled by the Node.js runtime. -Therefore, GraalVM JavaScript supports all modules supported by Node.js (including ES modules, CommonJS modules, and native modules). -2. In Java mode, GraalVM JavaScript can execute any JavaScript module or package that does not depend on native Node.js built-in modules (such as `'fs'`, `'http'`, etc.) +Therefore, GraalJS supports all modules supported by Node.js (including ES modules, CommonJS modules, and native modules). +2. In Java mode, GraalJS can execute any JavaScript module or package that does not depend on native Node.js built-in modules (such as `fs`, `http`, and so on). Modules can be loaded using a package bundler, or using the available built-in mechanisms for ES modules. -CommonJS modules are supported in Java mode under an experimental flag. +CommonJS modules are supported in Java mode under an experimental option. More details on JavaScript modules are available in [Modules](Modules.md). + +### Related Documentation + +* [Getting Started with Node.js](NodeJS.md) +* [Using JavaScript Modules and Packages in GraalJS](Modules.md) diff --git a/docs/user/OperatorOverloading.md b/docs/user/OperatorOverloading.md index 3bc7f564911..d3e23a3f9cd 100644 --- a/docs/user/OperatorOverloading.md +++ b/docs/user/OperatorOverloading.md @@ -4,28 +4,27 @@ toc_group: js link_title: Operator Overloading permalink: /reference-manual/js/OperatorOverloading/ --- + # Operator Overloading -GraalVM JavaScript provides an early implementation of the ECMAScript [operator overloading proposal](https://github.com/tc39/proposal-operator-overloading). +GraalJS provides an early implementation of the ECMAScript [operator overloading proposal](https://github.com/tc39/proposal-operator-overloading). This lets you overload the behavior of JavaScript's operators on your JavaScript classes. -If you want to experiment with this feature, you will first need to enable it. -Since both the proposal and our implementation of it are in early stages, you will need to set the following experimental option. - +If you want to experiment with this feature, enable it. +Since both the proposal and the GraalJS implementation of it are in early stages, you need to pass the `--experimental-options` option: ```shell js --experimental-options --js.operator-overloading ``` After setting the option, you will see a new builtin in the global namespace, the `Operators` function. You can call this function, passing it a JavaScript object as an argument. -The object should have a property for every operator you wish to overload, with the key being the name of the operator and the value being a function which implements it. +The object should have a property for every operator you wish to overload, with the key being the name of the operator and the value being a function that implements it. The return value of the `Operators` function is a constructor that you can then subclass when defining your type. -By subclassing this constructor, you get a class whose objects will all inherit the overloaded operator behavior that you defined in your argument to the `Operators` function. +By subclassing this constructor, you get a class whose objects inherit the overloaded operator behavior that you defined in your argument to the `Operators` function. ## Basic Example -Let's look at an example from the original proposal featuring vectors: - +Look at an example from the original proposal featuring vectors: ```java const VectorOps = Operators({ "+"(a, b) { @@ -46,12 +45,11 @@ class Vector extends VectorOps { } ``` -Here we define overloads for two operators, `+` and `==`. +Here two operators, `+` and `==`, are overloaded. Calling the `Operators` function with the table of overloaded operators yields the `VectorOps` class. -We then define our `Vector` class as a subclass of `VectorOps`. - -If we create instances of `Vector`, we can observe that they follow our overloaded operator definitions: +Then the `Vector` class is defined as a subclass of `VectorOps`. +If you create instances of `Vector`, you can observe that they follow the overloaded operator definitions: ``` > new Vector([1, 2, 3]) + new Vector([4, 5, 6]) == new Vector([5, 7, 9]) true @@ -59,8 +57,7 @@ true ## Example with Mixed Types -It is also possible to overload operators between values of different types, allowing, for example, multiplication of vectors by numbers. - +It is also possible to overload operators between values of different types, allowing, for example, multiplication of vectors by numbers: ```java const VectorOps = Operators({ "+"(a, b) { @@ -86,19 +83,18 @@ class Vector extends VectorOps { } ``` -To define mixed-type operators, we need to pass additional objects to the `Operators` function. -These extra tables should each have either a `left` property or a `right` property, depending on whether we are overloading the behavior of operators with some other type on the left or on the right side of the operator. -In our case, we are overloading the `*` operator for cases when there is a `Number` on the left and our type, `Vector`, on the right. -Each extra table can have either a `left` property or a `right` property and then any number of operator overloads which will apply to that particular case. - -Let's see this in action: +To define mixed-type operators, pass additional objects to the `Operators` function. +These extra tables should each have either a `left` property or a `right` property, depending on whether you overload the behavior of operators with some other type on the left or on the right side of the operator. +In the example, the `*` operator is overloaded for cases when there is a `Number` on the left and the type, `Vector`, on the right. +Each extra table can have either a `left` property or a `right` property and then any number of operator overloads that will apply to that particular case. +Running this example you see: ``` > 2 * new Vector([1, 2, 3]) == new Vector([2, 4, 6]) true ``` -## Reference +## Usage Documentation The function `Operators(table, extraTables...)` returns a class with overloaded operators. Users should define their own class which extends that class. @@ -106,7 +102,6 @@ Users should define their own class which extends that class. The `table` argument must be an object with one property for every overloaded operator. The property key must be the name of the operator. These are the names of operators which can be overloaded: - * binary operators: `"+"`, `"-"`, `"*"`, `"/"`, `"%"`, `"**"`, `"&"`, `"^"`, `"|"`, `"<<"`, `">>"`, `">>>"`, `"=="`, `"<"` * unary operators: `"pos"`, `"neg"`, `"++"`, `"--"`, `"~"` @@ -119,14 +114,13 @@ The value assigned to an operator name must be a function of two arguments in th The `table` argument can also have an `open` property. If so, the value of that property must be an array of operator names. -These are the operators which future classes will be able to overload on this type (e.g. a `Vector` type might declare `"*"` to be open so that later a `Matrix` type might overload the operations `Vector * Matrix` and `Matrix * Vector`). +These are the operators that future classes will be able to overload on this type (for example, a `Vector` type might declare `"*"` to be open so that later a `Matrix` type might overload the operations `Vector * Matrix` and `Matrix * Vector`). If the `open` property is missing, all operators are considered to be open for future overloading with other types. Following the first argument `table` are optional arguments `extraTables`. Each of these must also be an object. Each extra table must have either a `left` property or a `right` property, not both. The value of that property must be one of the following JavaScript constructors: - * `Number` * `BigInt` * `String` @@ -141,24 +135,24 @@ Similarly for the `right` property, if the extra table has a `right` property, t Note that you are free to overload any of the binary operators between your custom type and the JavaScript numeric types `Number` and `BigInt`. However, the only operators you are allowed to overload between your custom type and the `String` type are `"=="` and `"<"`. -The `Operators` function will return a constructor that you will usually want to extend in your own class. +The `Operators` function returns a constructor that you will usually want to extend in your own class. Instances of that class will respect your overloaded operator definitions. Whenever you use an operator on an object with overloaded operators, the following happens: - 1) Every operand that does *not* have overloaded operators is coerced to a primitive. 2) If there is an applicable overload for this pairing of operands, it is called. Otherwise, a `TypeError` is thrown. Notably, your objects with overloaded operators will not be coerced to primitives when applying operators and you can get `TypeError`s when applying undefined operators to them. There are two exceptions to this: - - 1) If you are using the `+` operator and one of the arguments is a string (or an object without overloaded operators that coerces to a string via `ToPrimitive`), then the result will be a concatenation of the `ToString` values of the two operands. + 1) If you are using the `+` operator and one of the arguments is a String (or an object without overloaded operators that coerces to a String via `ToPrimitive`), then the result will be a concatenation of the `ToString` values of the two operands. 2) If you are using the `==` operator and there is no applicable overload found, the two operands are assumed to be different (`x == y` will return `false` and `x != y` will return `true`). - ## Differences from the Proposal -There a few differences between the proposal (as defined by its specification and prototype implementation) and our implementation in GraalVM JavaScript: - - * You do not have to use the `with operators from` construction to enable the use of overloaded operators. When you overload operators for a class, those operators can then be used anywhere without using `with operators from`. Furthermore, our parser will not accept the `with operators from` clause as valid JavaScript. - * You cannot use decorators to define overloaded operators. At the time of implementing this proposal, GraalVM JavaScript does not support decorators (these are still an in-progress proposal). +There a few differences between the proposal (as defined by its specification and prototype implementation) and GraalJS implementation: + * You do not have to use the `with operators from` construction to enable the use of overloaded operators. When you overload operators for a class, those operators can then be used anywhere without using `with operators from`. Furthermore, the parser will not accept the `with operators from` clause as valid JavaScript. + * You cannot use decorators to define overloaded operators. At the time of implementing this proposal, GraalJS does not support decorators (these are still an in-progress proposal). * You cannot overload the `"[]"` and `"[]="` operators for reading and writing integer-indexed elements. These two operators require more complex treatment and are not currently supported. + +### Related Documentation + +* [ECMAScript operator overloading proposal](https://github.com/tc39/proposal-operator-overloading) \ No newline at end of file diff --git a/docs/user/Options.md b/docs/user/Options.md index 2f77989ac21..42511a4f69a 100644 --- a/docs/user/Options.md +++ b/docs/user/Options.md @@ -4,45 +4,46 @@ toc_group: js link_title: Options permalink: /reference-manual/js/Options/ --- + # Options Running JavaScript on GraalVM can be configured with several options. -## GraalVM JavaScript Launcher Options - -These options are to control the behaviour of the `js` launcher: -* `-e, --eval CODE `: evaluate the JavaScript source code, then exit the engine. -```shell -js -e 'print(1+2);' -``` -* `-f, --file FILE`: load and execute the provided script file. Note that the `-f` flag is optional and can be omitted in most cases, as any additional argument to `js` will be interpreted as file anyway. -```shell -js -f myfile.js -``` -* `--module FILE`: load and execute the provided module file. Note that `.mjs` files are treated as modules by default. -```shell -js --module myfile.mjs -``` -* `--version`: print the version information of GraalVM JavaScript, then exit. +These options are to control the behavior of the `js` launcher: +* `-e, --eval `: evaluate the JavaScript source code, then exit the engine. + ```shell + js -e 'print(1+2);' + ``` +* `-f, --file `: load and execute the provided script file. Note that the `-f` option is optional and can be omitted in most cases, as any additional argument to `js` will be interpreted as a file anyway. + ```shell + js -f myfile.js + ``` +* `--module `: load and execute the provided module file. Note that _.mjs_ files are treated as modules by default. + ```shell + js --module myfile.mjs + ``` +* `--version`: print the version information of GraalJS, then exit. * `--strict`: execute the engine in JavaScript's _strict mode_. -## GraalVM JavaScript Engine Options +## GraalJS Engine Options -There are several options to configure the behavior of the GraalVM JavaScript engine. +There are several options to configure the behavior of GraalJS. Depending on how the engine is started, the options can be passed either to the launcher or programmatically. For a full list of options of the JavaScript engine, pass the `--help:js` flag to the `js` launcher (available from GraalVM 22.1, for older releases use `--help:languages`). To include internal options, use `--help:js:internal`. -Note that those lists both include stable, supported options and experimental options. +Note that those lists both include stable, supported, and experimental options. + +### Pass Options on the Command Line -### Provide Options to the Launcher -To the launcher, the options are passed with `--js.=`: +To pass the options to the `js` launcher, use the `--js.=` syntax. For example: ```shell js --js.ecmascript-version=2015 ``` -### Provide Options Programmatically Using the Context API -When started from Java using GraalVM's Polyglot API, the options are passed programmatically to the `Context` object: +### Pass Options Programmatically Using the Context API + +When embedded in Java using GraalVM's Polyglot API, the options can be passed programmatically to the `Context` object: ```java Context context = Context.newBuilder("js") .option("js.ecmascript-version", "2015") @@ -52,39 +53,39 @@ context.eval("js", "42"); See the [Polyglot Programming](https://github.com/oracle/graal/blob/master/docs/reference-manual/polyglot-programming.md#passing-options-programmatically) reference for information on how to set options programmatically. -### Stable and Experimental Options +## Stable and Experimental Options -The available options are distinguished in stable and experimental options. -If an experimental option is used, an extra flag has to be provided upfront. +The available options are distinguished as stable and experimental options. +If an experimental option is used, an extra option has to be provided upfront. -In the native launchers (`js` and `node`), `--experimental-options` has to be passed before all experimental options. -When using a `Context`, the option `allowExperimentalOptions(true)` has to be called on the `Context.Builder`. +Using the `js` launcher, `--experimental-options` has to be passed before all experimental options. +When using a `Context`, the option `allowExperimentalOptions(true)` has to be called on a `Context.Builder`. See [ScriptEngine Implementation](ScriptEngine.md) on how to use experimental options with a `ScriptEngine`. ### Frequently Used Stable Options The following stable options are frequently relevant: - * `--js.ecmascript-version`: emulate a specific ECMAScript version. Integer value (`5`, `6`, etc., `2015`-`2022`), `"latest"` (latest supported version of the spec, including finished proposals), or `"staging"` (latest version including supported unfinished proposals), default is `"latest"`. - * `--js.foreign-object-prototype`: provide JavaScript's default prototype to foreign objects that mimic JavaScript's own types (foreign Arrays, Objects and Functions). Boolean value, default is `true`. + * `--js.ecmascript-version`: emulate a specific ECMAScript version. Integer value (`5`, `6`, etc., `2015`-`2022`), `"latest"` (latest supported version of the spec, including finished proposals), or `"staging"` (latest version including supported unfinished proposals). Default is `"latest"`. + * `--js.foreign-object-prototype`: provide JavaScript's default prototype to foreign objects that mimic JavaScript's own types (foreign Arrays, Objects, and Functions). Boolean value, default is `true`. * `--js.intl-402`: enable ECMAScript Internationalization API. Boolean value, default is `true`. - * `--js.regexp-static-result`: provide static `RegExp` properties containing the results of the last successful match, e.g., `RegExp.$1` (legacy). Boolean value, default is `true`. + * `--js.regexp-static-result`: provide static `RegExp` properties containing the results of the last successful match, for example, `RegExp.$1` (legacy). Boolean value, default is `true`. * `--js.strict`: enable strict mode for all scripts. Boolean value, default is `false`. * `--js.console`: enable the `console` global property. Boolean value, default is `true`. - * `--js.allow-eval`: allow the code generation from strings, e.g. using `eval()` or the `Function` constructor. Boolean value, default is `true`. - * `--js.timer-resolution`: sets the resolution of timing functions, like `Date.now()` and `performance.now()`, in nanoseconds. Default: `1000000` (i.e. 1 ms). - * `--js.unhandled-rejections`: configure unhandled promise rejection tracking. Accepted values are `none` (default, no tracking), `warn` (print a warning to stderr), `throw` (throw an exception), and `handler` (invoke a custom handler). + * `--js.allow-eval`: allow the code generation from strings, for example, using `eval()` or the `Function` constructor. Boolean value, default is `true`. + * `--js.timer-resolution`: sets the resolution of timing functions, such as `Date.now()` and `performance.now()`, in nanoseconds. Default: `1000000` (i.e. 1 ms). + * `--js.unhandled-rejections`: configure unhandled promise rejection tracking. Accepted values are `none` (default, no tracking), `warn` (print a warning to `stderr`), `throw` (throw an exception), and `handler` (invoke a custom handler). * `--js.esm-eval-returns-exports`: `context.eval` of an ES module `Source` returns its exported symbols. For a complete list, use `js --help:js:internal` #### ECMAScript Version -This option provides compatibility to a specific version of the ECMAScript specification. +The `--js.ecmascript-version` option provides compatibility with a specific version of the ECMAScript specification. It expects an integer value, where both the edition numbers (`5`, `6`, ...) and the publication years (starting from `2015`) are supported. -As of GraalVM 21.2, `latest`, `staging` are supported, too. +As of GraalVM 21.2, `latest`, `staging` are also supported. The default in GraalVM 23.1 is the [`ECMAScript 2023 specification`](https://262.ecma-international.org/14.0/). -GraalVM JavaScript implements some features of the future draft specification and of open proposals, if you explicitly select that version and/or enable specific experimental flags. -For production settings, it is recommended to set the `ecmascript-version` to a released, finalized version of the specification (e.g., `2022`). +GraalJS implements some features of the future draft specification and of open proposals, if you explicitly select that version and/or enable specific experimental options. +For production settings, it is recommended to set the `ecmascript-version` to a released, finalized version of the specification (for example, `2022`). Available versions are: * `5` for ECMAScript 5.x @@ -97,25 +98,32 @@ Available versions are: * `2021` (or `12`) for ECMAScript 2021 (**default** in 21.3) * `2022` (or `13`) for ECMAScript 2022 (**default** in 22.0+) * `2023` (or `14`) for [ECMAScript 2023](https://262.ecma-international.org/14.0/) (**default** in 23.1) +* `2024` (or `15`) for [ECMAScript 2024](https://262.ecma-international.org/15.0/) (**default** in 24.1) * `latest` for the latest supported language version (the default version) * `staging` for the latest supported language features including experimental unstable, unfinished [proposals](https://github.com/tc39/proposals) (_do not use in production!_) #### intl-402 -This option enables ECMAScript's [Internationalization API](https://tc39.github.io/ecma402/). +The `--js.intl-402` option enables ECMAScript's [Internationalization API](https://tc39.github.io/ecma402/). It expects a Boolean value and the default is `true`. #### Strict Mode -This option enables JavaScript's strict mode for all scripts. +The `--js.strict option enables JavaScript's strict mode for all scripts. It expects a Boolean value and the default is `false`. ### Frequently Used Experimental Options -Note that these options are experimental and are not guaranteed to be maintained or supported in the future. -To use them, the `--experimental-options` flag is required or the experimental options have to be enabled on the Context, see above. - - * `--js.nashorn-compat`: provide compatibility mode with the Nashorn engine. Sets ECMAScript version to 5 by default. Might conflict with newer ECMAScript versions. Boolean value, default is `false`. - * `--js.timezone`: set the local time zone. String value, default is the system default. - * `--js.v8-compat`: provide better compatibility with Google's V8 engine. Boolean value, default is `false`. - * `--js.temporal`: enable [`Temporal` API](https://github.com/tc39/proposal-temporal). - * `--js.webassembly`: enable `WebAssembly` API. + +Note that these options are experimental and are not guaranteed to be maintained or available in the future. +To use them, the `--experimental-options` option is required upfront. + +These are the frequently used experimental options: +* `--js.nashorn-compat`: provide compatibility mode with the Nashorn engine. Sets ECMAScript version to 5 by default. Might conflict with newer ECMAScript versions. Boolean value, default is `false`. +* `--js.timezone`: set the local time zone. String value, default is the system default. +* `--js.v8-compat`: provide better compatibility with Google's V8 engine. Boolean value, default is `false`. +* `--js.temporal`: enable [`Temporal` API](https://github.com/tc39/proposal-temporal). +* `--js.webassembly`: enable `WebAssembly` API. + +### Related Documentation + +* [Setting Options to ScriptEngine](ScriptEngine.md#setting-options-via-system-properties) \ No newline at end of file diff --git a/docs/user/README.md b/docs/user/README.md index 1339fe2045e..3a6e9758c1b 100644 --- a/docs/user/README.md +++ b/docs/user/README.md @@ -1,181 +1,192 @@ --- layout: docs toc_group: js -link_title: JavaScript and Node.js Reference +link_title: GraalJS permalink: /reference-manual/js/ --- -# GraalVM JavaScript and Node.js Runtime -GraalVM provides an ECMAScript-compliant runtime to execute JavaScript and Node.js applications. -It is fully standard compliant, executes applications with high performance, and provides all benefits from the GraalVM stack, including language interoperability and common tooling. -This reference documentation provides information on available JavaScript engine configurations, the Node.js runtime, the [`ScriptEngine` implementation](ScriptEngine.md), multithreading support details, possible embedding scenarios, and more. -To migrate the code previously targeted to the Nashorn or Rhino engines, [migration guides are available](NashornMigrationGuide.md). +# GraalJS -## Getting Started +GraalJS is a fast JavaScript language implementation built on top of GraalVM. +It is ECMAScript-compliant, provides interoperability with Java and other Graal languages, common tooling, and, if run on the GraalVM JDK, provides the best performance with the Graal JIT compiler by default. +You can also use GraalJS with Oracle JDK or OpenJDK. -As of GraalVM for JDK 21, the JavaScript (GraalJS) and Node.js runtimes are available as standalone distributions. -Two standalone language runtime options are available for both Oracle GraalVM and GraalVM Community Edition: a Native Image compiled native launcher or a JVM-based runtime (included). -To distinguish between them, the GraalVM Community Edition version has the suffix `-community` in the name: `graaljs-community---.tar.gz`, `graalnodejs-community---.tar.gz`. -A standalone that comes with a JVM has a `-jvm` suffix in a name. +GraalJS is a suitable replacement for projects wanting to [migrate from Nashorn or Rhino](#migration-guides) to a JavaScript engine that supports new ECMAScript standards and features. +You can easily add GraalJS to your Java application as shown below. -1. Navigate to [GitHub releases](https://github.com/oracle/graaljs/releases/) and select a desired standalone for your operating system. +## Getting Started with GraalJS on the JVM -2. Unzip the archive: +To embed JavaScript in a Java host application, enable GraalJS by adding it as a project dependency. +All necessary artifacts can be downloaded directly from Maven Central. +All artifacts relevant to embedders can be found in the Maven dependency group [org.graalvm.polyglot](https://central.sonatype.com/namespace/org.graalvm.polyglot). - > Note: If you are using macOS Catalina and later, first remove the quarantine attribute: - ```shell - sudo xattr -r -d com.apple.quarantine .tar.gz - ``` - Unzip: - ```shell - tar -xzf .tar.gz - ``` - Alternatively, open the file in the Finder. - -3. Check the version to see if the runtime is active: - ```shell - ./path/to/bin/js --version - ``` - ```shell - ./path/to/bin/node --version - ``` - -## Running JavaScript - -Use the `js` launcher to run plain JavaScript (ECMAScript) code: -```shell -js [options] [filename...] -- [args] -``` - -## Running Node.js - -The Node.js standalone provides `node` and `npm` launchers. - -Use the `node` utility to execute Node.js applications: -```shell -node [options] [filename] [args] -``` -The `npm` command is equivalent to the default Node.js command and supports all Node.js APIs. - -1. Install the `colors` and `ansispan` packages using `npm install` as follows: - ```shell - npm install colors ansispan - ``` - After the packages are installed, you can use them from your application. - -2. Add the following code snippet to a file named `app.js` and save it in the same directory where you installed the Node.js packages: - ```js - const http = require("http"); - const span = require("ansispan"); - require("colors"); - - http.createServer(function (request, response) { - response.writeHead(200, {"Content-Type": "text/html"}); - response.end(span("Hello Graal.js!".green)); - }).listen(8000, function() { console.log("Graal.js server running at http://127.0.0.1:8000/".red); }); - - setTimeout(function() { console.log("DONE!"); process.exit(); }, 2000); - ``` - -3. Execute it on GraalVM using the `node` command as follows: - ```shell - node app.js - ``` - -For more information about running Node.js, go to [Node.js Runtime](NodeJS.md). -The Node.js functionality is available when an application is started from the `node` binary launcher. -Certain limits apply when launching a Node.js application or accessing NPM packages from a Java context, see [Node.js vs. Java Script Context](NodeJSVSJavaScriptContext.md). - -## Interoperability with Java - -To embed JavaScript in a Java host application, enable JavaScript by adding it as a project dependency. Below is the Maven configuration for a JavaScript embedding: ```xml org.graalvm.polyglot polyglot - ${graalvm.version} + ${graaljs.version} org.graalvm.polyglot js - ${graalvm.version} + ${graaljs.version} pom ``` -It enables the Oracle GraalVM JavaScript runtime by default. -Use `js-community` if you need the artifact built on top of GraalVM Community Edition. - -To access Java from JavaScript, use `Java.type`, as in the following example: -```shell -node -> var BigInteger = Java.type('java.math.BigInteger'); -> console.log(BigInteger.valueOf(2).pow(100).toString(16)); -10000000000000000000000000 -``` +This enables GraalJS which is built on top of Oracle GraalVM and licensed under the [GraalVM Free Terms and Conditions (GFTC)](https://www.oracle.com/downloads/licenses/graal-free-license.html). +Use `js-community` if you want to use GraalJS built on GraalVM Community Edition. -Vice versa, you can execute JavaScript from Java by embedding the JavaScript context in the Java program: -```java -import org.graalvm.polyglot.*; -import org.graalvm.polyglot.proxy.*; +Go step-by-step to create a Maven project, embedding JavaScript in Java, and run it. +This example application was tested with GraalVM for JDK 22 and the GraalVM Polyglot API version 24.0.2. +See how to install GraalVM on the [Downloads page](https://www.graalvm.org/downloads/). -public class HelloPolyglot { +1. Create a new Maven Java project named "app" in your favorite IDE or from your terminal with the following structure: + ``` + ├── pom.xml + └── src + ├── main + │   └── java + │   └── com + │   └── example + │   └── App.java + ``` + For example, you can run this command to create a new Maven project using the quickstart archetype: + ```bash + mvn archetype:generate -DgroupId=com.example -DartifactId=app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false + ``` - static String JS_CODE = "(function myFun(param){console.log('hello '+param);})"; +2. Replace the contents of _App.java_ with the following code: + ```java + package com.example; - public static void main(String[] args) { - System.out.println("Hello Java!"); - try (Context context = Context.create()) { - Value value = context.eval("js", JS_CODE); - value.execute(args[0]); - } - } -} -``` -By wrapping the function definition (`()`), you return the function immediately. -The source code unit can be represented with a String, as in the example, a file, read from URL, and [other means](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Source.html). + import org.graalvm.polyglot.*; + import org.graalvm.polyglot.proxy.*; + + public class App { -This way you can evaluate JavaScript context embedded in Java, but you will not be able to call a function and set parameters in the function directly from the Java code. + static String JS_CODE = "(function myFun(param){console.log('hello '+param);})"; -The Node.js runtime cannot be embedded into a JVM but has to be started as a separate process. + public static void main(String[] args) { + System.out.println("Hello JavaScript from Java"); + try (Context context = Context.create()) { + Value value = context.eval("js", JS_CODE); + value.execute(args[0]); + } + } + } + ``` -For example, save this code as _app.js_: -```js -var HelloPolyglot = Java.type("HelloPolyglot"); +3. Add the regular Maven plugins for compiling and assembling the project into a JAR file with all dependencies to your _pom.xml_ file: + ```xml + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + true + + + + org.apache.maven.plugins + maven-assembly-plugin + ${maven-assembly-plugin.version} + + + + com.example.App + + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + + ``` -HelloPolyglot.main(["from node.js"]); +4. Add the following dependencies to _pom.xml_ to include the JavaScript engine (GraalJS): + ```xml + + + org.graalvm.polyglot + polyglot + ${graaljs.version} + + + org.graalvm.polyglot + js + ${graaljs.version} + pom + + + ``` + Set the `${graaljs.version}` property to the GraalVM Polyglot API version. For this example, use `24.0.2`. -console.log("done"); +5. Package the project and run the application: + ```bash + mvn clean package + ``` + ```bash + java -jar target/helloworld-1.0-SNAPSHOT-jar-with-dependencies.jar GraalVM + ``` + + This example application uses the [Polyglot API](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/package-summary.html) and returns a JavaScript function as a Java value. + A single JAR with all dependencies was created from language libraries. + However, we recommend splitting and using Java modules on the module path, especially if you would like to compile this application ahead of time with GraalVM Native Image. + Learn more in the [Guide to Embedding Languages](https://www.graalvm.org/reference-manual/embed-languages/#dependency-setup). + +The source code unit can be represented with a String, as in the example, a file, read from URL, and [other means](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Source.html). +By wrapping the function definition (`()`), you return the function immediately: +```java +Value f = context.eval("js", "(function f(x, y) { return x + y; })"); +Value result = f.execute(19, 23); ``` -Then run it: -```shell -node --vm.cp=. app.js -Hello Java! -hello from node.js -done +You can also lookup Java types from JavaScript and instantiate them, as demonstrated below: +```java +try (Context context = Context.newBuilder() + .allowHostAccess(HostAccess.newBuilder(HostAccess.ALL).build()) + .allowHostClassLookup(className -> true) + .build()) { + java.math.BigDecimal v = context.eval("js", + "var BigDecimal = Java.type('java.math.BigDecimal');" + + "BigDecimal.valueOf(10).pow(20)") + .asHostObject(); + assert v.toString().equals("100000000000000000000"); +} ``` -Both Node.js and JVM then run in the same process and the interoperability works using the same `Value` classes as above. - -Learn more about language interoperability in the [Java Interoperability](JavaInteroperability.md) guide. +The Polyglot API offers many other ways to access a guest language code from Java, for example, by directly accessing JavaScript objects, numbers, strings, and arrays. +Learn more about JavaScript to Java interoperability and find more examples in the [Java Interoperability guide](JavaInteroperability.md). -## Further documentation +### Related Documentation -For additional information, see the following documentation. +GraalJS is also available as a standalone distribution that you can download from [GitHub](https://github.com/oracle/graaljs/releases). +Learn more [here](https://github.com/oracle/graaljs/blob/master/README.md#standalone-distributions). -Using GraalVM JavaScript: +We provide the following documentation for GraalJS users: * [JavaScript Compatibility](JavaScriptCompatibility.md) -* [Options and Flags to the Engine](Options.md) -* [Multithreading Support](Multithreading.md) * [Java Interoperability](JavaInteroperability.md) -* [Execute GraalVM JavaScript on a Stock JDK](RunOnJDK.md) +* [Options of the JavaScript Engine](Options.md) +* [Multithreading Support](Multithreading.md) +* [Execute GraalJS on a Stock JDK](RunOnJDK.md) + +#### Migration Guides -Legacy environments: +Learn more about migration from legacy environments: * [Migration Guide from Nashorn](NashornMigrationGuide.md) * [Migration Guide from Rhino](RhinoMigrationGuide.md) -* [Work with a javax.script.ScriptEngine](ScriptEngine.md) - -Node.js support: -* [Node.js Support](NodeJS.md) -* [Differences between node's native launcher and a Java Context](NodeJSVSJavaScriptContext.md) +* [Work with ScriptEngine](ScriptEngine.md) \ No newline at end of file diff --git a/docs/user/RhinoMigrationGuide.md b/docs/user/RhinoMigrationGuide.md index 7bc72609c29..f8c2ee3c66e 100644 --- a/docs/user/RhinoMigrationGuide.md +++ b/docs/user/RhinoMigrationGuide.md @@ -1,36 +1,47 @@ --- layout: docs toc_group: js -link_title: Migration Guide from Rhino to GraalVM JavaScript +link_title: Migration Guide from Rhino to GraalJS permalink: /reference-manual/js/RhinoMigrationGuide/ --- -# Migration Guide from Rhino to GraalVM JavaScript + +# Migration Guide from Rhino to GraalJS This document serves as a migration guide for code previously targeted to the Rhino engine. -See the [Java Interoperability](JavaInteroperability.md) guide for an overview of supported features. +See the [Java Interoperability guide](JavaInteroperability.md) for an overview of supported features. -Both Rhino and GraalVM JavaScript support a similar set of syntax and semantics for Java interoperability. -The most important differences relevant for migration are listed here. +Both Rhino and GraalJS support a similar set of syntax and semantics for Java interoperability. +The most important differences relevant for migrations are listed here. ### `Java.type(typename)` instead of `java.a.b.c.typename` -GraalVM JavaScript does not put available Java classes in the JavaScript scope. + +GraalJS does not put available Java classes in the JavaScript scope. You have to explicitly load the classes using `Java.type(typename)`. -GraalVM JavaScript supports the `Packages` global object, but loading the classes explicitly is still encouraged. -The following Java package globals are available in Nashorn compatibility mode (`js.nashorn-compat` option): `java`, `javafx`, `javax`, `com`, `org`, `edu`. + +GraalJS supports the `Packages` global object, but loading the classes explicitly is still encouraged. +The following Java package globals are available in the Nashorn compatibility mode (`js.nashorn-compat` option): `java`, `javafx`, `javax`, `com`, `org`, `edu`. ### Console Output of Java Classes and Java Objects -GraalVM JavaScript provides a `print` builtin function. + +GraalJS provides the `print` builtin function. It tries to special-case its behavior on Java classes and Java objects to provide the most useful output. -Note that GraalVM JavaScript also provides a `console.log` function. +Note that GraalJS also provides a `console.log` function. This is an alias for `print` in pure JavaScript mode, but uses an implementation provided by Node.js when in Node mode. The behavior around interop objects differs for `console.log` in Node mode as it does not implement special treatment for such objects. ### JavaScript vs Java Strings -GraalVM JavaScript uses Java strings internally to represent JavaScript strings. + +GraalJS uses Java strings internally to represent JavaScript strings. This makes it impossible to differentiate whether a specific string was created by JavaScript or by Java code. -In GraalVM JavaScript, the JavaScript properties take precedence over Java fields or methods. +In GraalJS, the JavaScript properties take precedence over Java fields or methods. For instance, you can query the `length` property (of JavaScript) but you cannot call the `length` function (of Java) on JavaScript strings - `length` behaves like a data property, not like a function. ### JavaImporter -The `JavaImporter` feature is available only in Nashorn compatibility mode (`js.nashorn-compat` option). + +The `JavaImporter` feature is available only in the Nashorn compatibility mode (`js.nashorn-compat`). + +### Related Documentation + +* [Migration Guide from Nashorn to GraalJS](NashornMigrationGuide.md) +* [Java Interoperability](JavaInteroperability.md) \ No newline at end of file diff --git a/docs/user/RunOnJDK.md b/docs/user/RunOnJDK.md index 76f25c749d7..4d875b3bb89 100644 --- a/docs/user/RunOnJDK.md +++ b/docs/user/RunOnJDK.md @@ -1,46 +1,46 @@ --- layout: docs toc_group: js -link_title: Run GraalVM JavaScript on a Stock JDK +link_title: Run GraalJS on a Stock JDK permalink: /reference-manual/js/RunOnJDK/ --- -# Run GraalVM JavaScript on a Stock JDK -GraalVM JavaScript is optimized for execution as part of GraalVM, or in an embedding scenario built on GraalVM. -This guarantees best possible performance by using the [GraalVM compiler](https://github.com/oracle/graal) as the optimizing compiler, and potentially [Native Image](https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/README.md) to ahead-of-time compile the engine into a native binary. +# Run GraalJS on a Stock JDK -As GraalVM JavaScript is a Java application, it is possible to execute it on a stock Java VM like OpenJDK. +GraalJS is optimized for execution as part of GraalVM, primarily recommended for use in a Java application. +This guarantees the best possible performance by using the [Graal compiler](https://www.graalvm.org/reference-manual/java/compiler/) as the optimizing compiler, and potentially [Native Image](https://github.com/oracle/graal/blob/master/docs/reference-manual/native-image/README.md) to compile the engine ahead of time into a native binary. + +It is, however, possible to execute GraalJS on a standard Java VM such as Oracle JDK or OpenJDK. When executed without the Graal Compiler, JavaScript performance will be significantly worse. -While the JIT compilers available on stock JVMs can execute and JIT-compile the GraalVM JavaScript codebase, they cannot optimize it to its full performance potential. -This document describes how to run GraalVM JavaScript on stock Java VMs, and shows how you can use the GraalVM compiler as a JIT compiler to guarantee the best possible performance. +While the JIT compiler available on a standard JVM can execute and JIT-compile the GraalJS codebase, it cannot optimize GraalJS to its full performance potential. +This document describes how to run GraalJS on a standard Java VM, and shows how you can use the Graal compiler as a JIT compiler to guarantee the best possible performance. + +## GraalJS on Maven Central -## GraalVM JavaScript on Maven Central -GraalVM JavaScript is open source and regularly pushed to Maven Central Repository by the community. -You can find it as a POM artifact, under [`org.graalvm.polyglot:js`](https://mvnrepository.com/artifact/org.graalvm.polyglot/js). +GraalJS is open source and regularly pushed to Maven Central Repository by the community. +You can find it under [`org.graalvm.polyglot:js`](https://mvnrepository.com/artifact/org.graalvm.polyglot/js). -There are example Maven projects for GraalVM JavaScript on JDK 21 (or later) using the Graal compiler: +We provide example projects running GraalJS embedded in Java on JDK 21 (or later) and using the Graal compiler: * [Polyglot Embedding Demo](https://github.com/graalvm/polyglot-embedding-demo). -Example Maven and Gradle projects for a simple JavaScript "Hello World" application. +Maven and Gradle projects for a simple JavaScript "Hello World" application. * [JS Maven Demo](https://github.com/oracle/graaljs/tree/master/graal-js/test/maven-demo). This example contains a Maven project for a JavaScript benchmark (a prime number generator). -It allows a user to compare the performance of GraalVM JavaScript running with or without the GraalVM compiler as the optimizing compiler. -Running with the GraalVM compiler will significantly improve the execution performance of any relatively large JavaScript codebase. +It enables a user to compare the performance of GraalJS running with or without the Graal compiler as the optimizing compiler. +Running with the Graal compiler significantly improves the execution performance of any relatively large JavaScript codebase. +In essence, the example _pom.xml_ file activates the JVM Compiler Interface (JVMCI) and configures the JIT compiler to be the Graal compiler by providing it on `--module-path` and `--upgrade-module-path`. -In essence, the example `pom.xml` file activates the JVM Compiler Interface (JVMCI) and configures the JIT compiler to be the Graal compiler by providing it on `--module-path` and `--upgrade-module-path`. +## ScriptEngine JSR 223 -### ScriptEngine JSR 223 -GraalVM JavaScript can be started via `ScriptEngine` when _js-scriptengine.jar_ is included on the module path. +GraalJS can be started via `ScriptEngine` when _js-scriptengine.jar_ is included on the module path. The engine registers under several different names, including `Graal.js`, `js`, `JavaScript`, and `javascript`. Note that the Nashorn engine might be available under its names as well, if on the module path. -To start GraalVM JavaScript from `ScriptEngine`, the following code can be used: - +To start GraalJS from `ScriptEngine`, the following code can be used: ```java new ScriptEngineManager().getEngineByName("Graal.js"); ``` To list all available engines: - ```java List engines = new ScriptEngineManager().getEngineFactories(); for (ScriptEngineFactory f : engines) { @@ -49,10 +49,14 @@ for (ScriptEngineFactory f : engines) { ``` ### Inspecting the Setup - Is the GraalVM Compiler Used as a JIT Compiler? -The `--engine.TraceCompilation` flag enables a debug output whenever a JavaScript method is compiled by the GraalVM compiler. -JavaScript source code with long-enough run time will trigger the compilation and print a log output: +The `--engine.TraceCompilation` option enables a debug output whenever a JavaScript method is compiled by the Graal compiler. +JavaScript source code with a long-enough run time will trigger the compilation and print a log output: ```shell > function add(a,b) { return a+b; }; for (var i=0;i<1000*1000;i++) { add(i,i); } [truffle] opt done add |ASTSize 7/ 7 |Time 99( 90+9 )ms |DirectCallNodes I 0/D 0 |GraalNodes 22/ 71 |CodeSize 274 |CodeAddress 0x7f76e4c1fe10 |Source :1:1 ``` + +### Related Documentation + +* [Getting Started with GraalJS on the JVM](README.md) \ No newline at end of file diff --git a/docs/user/ScriptEngine.md b/docs/user/ScriptEngine.md index 4734e7d4dea..0fa0f1bef64 100644 --- a/docs/user/ScriptEngine.md +++ b/docs/user/ScriptEngine.md @@ -4,42 +4,40 @@ toc_group: js link_title: ScriptEngine Implementation permalink: /reference-manual/js/ScriptEngine/ --- -# ScriptEngine Implementation -GraalVM provides a JSR-223 compliant `javax.script.ScriptEngine` implementation for running JavaScript. -Note that this feature is provided for legacy reasons in order to allow easier migration for implementations currently based on a `ScriptEngine`. -We strongly encourage users to use the `org.graalvm.polyglot.Context` interface in order to control many of the settings directly and benefit from finer-grained security settings in GraalVM. +# ScriptEngine Implementation -## Prerequisite +GraalJS provides a JSR-223 compliant `javax.script.ScriptEngine` implementation for running JavaScript. +Note that this feature is provided for legacy reasons to allow easier migration for implementations currently based on a `ScriptEngine`. +We strongly encourage users to use the `org.graalvm.polyglot.Context` interface to control many of the settings directly and benefit from finer-grained security settings in GraalVM. -NOTE: As of GraalVM for JDK 21, GraalVM no longer includes `ScriptEngine` by default. -If you relied on that, you will have to migrate your setup to explicitly depend on the script engine module and add it to the _module path_. +> Note: As of GraalVM for JDK 21, GraalVM no longer includes `ScriptEngine` by default. If you relied on that, you will have to migrate your setup to explicitly depend on the script engine module and add it to the _module path_. -To get the `js-scriptengine` module, use a Maven dependency, like follows: +To enable the `js-scriptengine` module, add it as the Maven dependency, as follows: ```xml org.graalvm.js js-scriptengine - ${graalvm.version} + ${graaljs.version} - org.graalvm.js + org.graalvm.polyglot js - ${graalvm.version} - runtime + ${graaljs.version} + pom ``` -If you are not using `mvn`, you will need to add the `js-scriptengine.jar` file to the module path manually, for example: `--module-path=languages/js/graaljs-scriptengine.jar`. -In some case, you may also need to add `--add-modules org.graalvm.js.scriptengine` to the command line, to ensure that the `ScriptEngine` will be found. +If you are not using Maven, you will need to add the _js-scriptengine.jar_ file to the module path manually, for example, `--module-path=languages/js/graaljs-scriptengine.jar`. +In some cases you may also need to add `--add-modules org.graalvm.js.scriptengine` to the command line, to ensure that the `ScriptEngine` will be found. An explicit dependency on the `org.graalvm.js.scriptengine` module is only required if you want to use `GraalJSScriptEngine` directly (see below). -Finally, it is also possible to use `jlink` to generate a custom Java runtime image that contains the JS `ScriptEngine`. +Finally, it is also possible to use `jlink` to generate a custom Java runtime image that contains the GraalJS's `ScriptEngine`. -An example `pom.xml` can be found [in the GraalJS repository on GitHub](https://github.com/oracle/graaljs/blob/master/graal-js/test/maven-demo/pom.xml). +An example _pom.xml_ file can be found in the [GraalJS repository on GitHub](https://github.com/oracle/graaljs/blob/master/graal-js/test/maven-demo/pom.xml). -## Recommendation: Use `CompiledScript` API +## Recommendation for Use -To avoid unnecessary re-compilation of JS sources, it is recommended to use `CompiledScript.eval` instead of `ScriptEngine.eval`. +To avoid unnecessary recompilation of JavaScript sources, **it is recommended to use `CompiledScript.eval`** instead of `ScriptEngine.eval`. This prevents JIT-compiled code from being garbage-collected as long as the corresponding `CompiledScript` object is alive. Single-threaded example: @@ -71,9 +69,9 @@ script.eval(); ``` ## Setting Options via `Bindings` -The `ScriptEngine` interface does not provide a default way to set options. -As a workaround, `GraalJSScriptEngine` supports setting some `Context` options -through `Bindings`. + +The `ScriptEngine` interface does not provide a default way to set options. +As a workaround, `GraalJSScriptEngine` supports setting some `Context` options through `Bindings`. These options are: * `polyglot.js.allowHostAccess ` * `polyglot.js.allowNativeAccess ` @@ -88,10 +86,10 @@ These options are: These options control the sandboxing rules applied to evaluated JavaScript code and are set to `false` by default, unless the application was started in the Nashorn compatibility mode (`--js.nashorn-compat=true`). Note that using `ScriptEngine` implies allowing experimental options. -This is an exhaustive list of allowed options to be passed via Bindings; in case you need to pass additional options to GraalVM JavaScript, you need to manually create a `Context` as shown below. +This is an exhaustive list of allowed options to be passed via `Bindings`; in case you need to pass additional options to GraalJS, you need to manually create a `Context` as shown below. -To set an option via `Bindings`, use `Bindings.put(