diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 00000000000..26d33521af1 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000000..aa345419dc0 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000000..35eb1ddfbbc --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/TemporalInteropTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/TemporalInteropTest.java new file mode 100644 index 00000000000..5720f91a7f9 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/builtins/TemporalInteropTest.java @@ -0,0 +1,1111 @@ +/* + * Copyright (c) 2020, 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.truffle.js.test.builtins; + +import static com.oracle.truffle.js.lang.JavaScriptLanguage.ID; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.time.Duration; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZoneId; + +import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.HostAccess; +import org.graalvm.polyglot.PolyglotException; +import org.graalvm.polyglot.Value; +import org.junit.Assert; +import org.junit.Test; +import org.junit.Ignore; + +import com.oracle.truffle.js.runtime.JSContextOptions; +import com.oracle.truffle.js.test.JSTest; + +public class TemporalInteropTest extends JSTest { + + @Ignore // dont know why it fails + @Test + public void testInstantGetter() { + String code = "javaInst.epochMilliseconds;"; + + java.time.Instant inst = Instant.ofEpochMilli(100_000_000); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaInst", inst); + Value result = ctx.eval(ID, code); + Assert.assertEquals(100_000_000L, result.asLong()); + } + } + + @Test + public void testInstantAdd() { + String code = "javaInst.add(Temporal.Duration.from('PT1H')).epochMilliseconds;"; + + java.time.Instant inst = Instant.ofEpochMilli(100_000_000); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaInst", inst); + Value result = ctx.eval(ID, code); + Assert.assertEquals(103_600_000L, result.asLong()); + } + } + + @Test + public void testInstantSubtract() { + String code = "javaInst.subtract(Temporal.Duration.from('PT1H')).epochMilliseconds;"; + + java.time.Instant inst = Instant.ofEpochMilli(100_000_000); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaInst", inst); + Value result = ctx.eval(ID, code); + Assert.assertEquals(96_400_000L, result.asLong()); + } + } + @Ignore // arity error + @Test + public void testInstantUntil() { + String code = "javaInst.until(new Temporal.Instant(BigInt(3_000_000))).milliseconds;"; + + java.time.Instant inst = Instant.ofEpochMilli(1); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaInst", inst); + Value result = ctx.eval(ID, code); + Assert.assertEquals(2, result.asLong()); + } + } + + @Test + public void testInstantSince() { + String code = "javaInst.since(new Temporal.Instant(BigInt(1_000_000))).milliseconds;"; + + java.time.Instant inst = Instant.ofEpochMilli(3); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaInst", inst); + Value result = ctx.eval(ID, code); + Assert.assertEquals(2, result.asLong()); + } + } + + @Test + public void testInstantSince2() { + String code = "new Temporal.Instant(BigInt(3_000_000)).since(javaInst).milliseconds;"; + + java.time.Instant inst = Instant.ofEpochMilli(1); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaInst", inst); + Value result = ctx.eval(ID, code); + Assert.assertEquals(2, result.asLong()); + } + } + + @Test + public void testInstantUntil2() { + String code = "new Temporal.Instant(BigInt(1_000_000)).until(javaInst).milliseconds;"; + + java.time.Instant inst = Instant.ofEpochMilli(3); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaInst", inst); + Value result = ctx.eval(ID, code); + Assert.assertEquals(2, result.asLong()); + } + } + + @Test + public void testInstantRound() { + String code = "javaInst.round('second').epochSeconds;"; + + java.time.Instant inst = Instant.ofEpochMilli(1_000_203); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaInst", inst); + Value result = ctx.eval(ID, code); + Assert.assertEquals(1000, result.asLong()); + } + } + + @Test + public void testInstantEquals() { + String code = "new Temporal.Instant(BigInt(100_000_000)).equals(javaInst);"; + + java.time.Instant inst = Instant.ofEpochMilli(100); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaInst", inst); + Value result = ctx.eval(ID, code); + Assert.assertEquals(true, result.asBoolean()); + } + } + @Ignore // arity error + @Test + public void testInstantEquals2() { + String code = "javaInst.equals(new Temporal.Instant(BigInt(100_000_000)));"; + + java.time.Instant inst = Instant.ofEpochMilli(100); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaInst", inst); + Value result = ctx.eval(ID, code); + assertTrue(result.asBoolean()); + } + } + + @Test + public void testInstantToStringOnlyJS() { + String code = "new Temporal.Instant(BigInt(1_574_074_321_816_000_000)).toString();"; + + //java.time.Instant inst = Instant.ofEpochMilli(123_456_789); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + //ctx.getBindings(ID).putMember("javaInst", inst); + Value result = ctx.eval(ID, code); + Assert.assertEquals("2019-11-18T10:52:01.816Z", result.toString()); + } + } + + @Test + public void testInstantToString() { + String code = "javaInst.toString();"; + + java.time.Instant inst = Instant.ofEpochMilli(1_574_074_321_816L); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaInst", inst); + Value result = ctx.eval(ID, code); + Assert.assertEquals("2019-11-18T10:52:01.816Z", result.toString()); + } + } + + @Test + public void testInstantToZonedDateTime() { + String code = "timeZone = Temporal.TimeZone.from('Asia/Tokyo'); " + + "calendar = Temporal.Calendar.from('japanese'); " + + "javaInst.toZonedDateTime({ timeZone, calendar }).toString();"; + + java.time.Instant inst = Instant.ofEpochMilli(0); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaInst", inst); + Value result = ctx.eval(ID, code); + Assert.assertEquals("1970-01-01T09:00:00+09:00[Asia/Tokyo][u-ca=japanese]", result.toString()); + } + } + + @Test + public void testInstantToZonedDateTimeISO() { + String code = "javaInst.toZonedDateTimeISO('UTC').year"; + + java.time.Instant inst = Instant.ofEpochMilli(0); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaInst", inst); + Value result = ctx.eval(ID, code); + Assert.assertEquals(1970, result.asLong()); + } + } + + // ============================================================================================================== // + // Temporal Duration + // ============================================================================================================== // + + @Ignore + @Test + public void testDurationGetter() { + String code = "javaDur.hours;"; + + java.time.Duration dur = Duration.ofHours(12); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDur", dur); + Value result = ctx.eval(ID, code); + Assert.assertEquals(12, result.asLong()); + } + } + + @Test + public void testDurationWith() { + String code = "javaDur.with({hours: 50}).hours;"; + + java.time.Duration dur = Duration.ofHours(12); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDur", dur); + Value result = ctx.eval(ID, code); + Assert.assertEquals(50, result.asLong()); + } + } + + @Test + public void testDurationAdd() { + String code = "javaDur.add({hours: 50}).hours"; + + java.time.Duration dur = Duration.ofHours(12); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDur", dur); + Value result = ctx.eval(ID, code); + Assert.assertEquals(62, result.asLong()); + } + } + + @Test + public void testDurationAdd2() { + String code = "javaDur.add(javaDur).hours"; + + java.time.Duration dur = Duration.ofHours(12); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDur", dur); + Value result = ctx.eval(ID, code); + Assert.assertEquals(24, result.asLong()); + } + } + + @Test + public void testDurationSubtract() { + String code = "javaDur.subtract({hours: 5}).hours"; + + java.time.Duration dur = Duration.ofHours(12); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDur", dur); + Value result = ctx.eval(ID, code); + Assert.assertEquals(7, result.asLong()); + } + } + + @Test + public void testDurationSubtract2() { + String code = "javaDur.subtract(javaDur).hours"; + + java.time.Duration dur = Duration.ofHours(12); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDur", dur); + Value result = ctx.eval(ID, code); + Assert.assertEquals(0, result.asLong()); + } + } + + @Ignore // negated() does exist for java Duration. + @Test + public void testDurationNegated() { + String code = "javaDur.negated().hours"; + + java.time.Duration dur = Duration.ofHours(12); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDur", dur); + Value result = ctx.eval(ID, code); + Assert.assertEquals(-12, result.asLong()); + } + } + + @Ignore // abs() exists for java Duration + @Test + public void testDurationAbs() { + String code = "javaDur.abs().hours"; + + java.time.Duration dur = Duration.ofHours(-12); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDur", dur); + Value result = ctx.eval(ID, code); + Assert.assertEquals(12, result.asLong()); + } + } + + @Test + public void testDurationRound() { + String code = "javaDur.round('minute').minutes"; + + java.time.Duration dur = Duration.ofSeconds(95); // same as 1minute and 35 seconds, rounded up to 2 minutes + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDur", dur); + Value result = ctx.eval(ID, code); + Assert.assertEquals(2, result.asLong()); + } + } + + @Test + public void testDurationTotal() { + String code = "javaDur.total({unit: 'second'})"; + + java.time.Duration dur = Duration.ofMinutes(2); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDur", dur); + Value result = ctx.eval(ID, code); + Assert.assertEquals(120, result.asLong()); + } + } + + @Test + public void testDurationToString() { + String code = "javaDur.toString();"; + + java.time.Duration dur = Duration.ofHours(10); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDur", dur); + Value result = ctx.eval(ID, code); + Assert.assertEquals("PT10H", result.toString()); + } + } + + @Test + public void testDurationToJSON() { + String code = "javaDur.toJSON();"; + + java.time.Duration dur = Duration.ofHours(10); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDur", dur); + Value result = ctx.eval(ID, code); + Assert.assertEquals("PT10H", result.toString()); + } + } + + @Test + public void testDurationToLocaleString() { + String code = "javaDur.toLocaleString();"; + + java.time.Duration dur = Duration.ofHours(10); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDur", dur); + Value result = ctx.eval(ID, code); + Assert.assertEquals("PT10H", result.toString()); + } + } + + @Test(expected = RuntimeException.class) + public void testDurationValueOf() { + String code = "javaDur.valueOf();"; + + java.time.Duration dur = Duration.ofHours(10); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDur", dur); + Value result = ctx.eval(ID, code); + Assert.assertEquals("PT10H", result.toString()); + } + } + + // ============================================================================================================== // + // Temporal PlainDate + // ============================================================================================================== // + + @Ignore // Unsupported operation identifier 'adjustInto' and object '{day: 1}'(language: JavaScript, type: Object). Identifier is not executable or instantiable. + @Test + public void testPlainDateWith() { + //String code = "Temporal.PlainDate.from('2006-01-24').with({day: 1}).toString();"; + String code = "javaDate.with({day: 1}).toString();"; + + java.time.LocalDate date = LocalDate.of(2000, 1, 24); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDate", date); + Value result = ctx.eval(ID, code); + Assert.assertEquals("2006-01-01", result.toString()); + } + } + @Test + public void testPlainDateWithCalendar() { + String code = "javaDate.withCalendar('gregory').toString();"; + + java.time.LocalDate date = LocalDate.of(2000, 1, 24); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDate", date); + Value result = ctx.eval(ID, code); + Assert.assertEquals("2000-01-24[u-ca=gregory]", result.toString()); + } + } + + @Test + public void testPlainDateAdd() { + String code = "javaDate.add({years: 22}).toString();"; + + java.time.LocalDate date = LocalDate.of(2000, 1, 24); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDate", date); + Value result = ctx.eval(ID, code); + Assert.assertEquals("2022-01-24", result.toString()); + } + } + + @Test + public void testPlainDateSubtract() { + String code = "javaDate.subtract({years: 10}).toString();"; + + java.time.LocalDate date = LocalDate.of(2000, 1, 24); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDate", date); + Value result = ctx.eval(ID, code); + Assert.assertEquals("1990-01-24", result.toString()); + } + } + + @Test + public void testPlainDateUntil() { + //String code = "javaDate.until(Temporal.PlainDate.from('2000-01-25')).toString();"; // arity error + String code = "Temporal.PlainDate.from('2000-01-24').until(javaDate).toString();"; + + java.time.LocalDate date = LocalDate.of(2000, 1, 25); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDate", date); + Value result = ctx.eval(ID, code); + Assert.assertEquals("P1D", result.toString()); + } + } + + @Test + public void testPlainDateSince() { + String code = "javaDate.since(Temporal.PlainDate.from('2000-01-24')).toString();"; + + java.time.LocalDate date = LocalDate.of(2000, 1, 25); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDate", date); + Value result = ctx.eval(ID, code); + Assert.assertEquals("P1D", result.toString()); + } + } + + @Test + public void testPlainDateEquals() { + //String code = "javaDate.equals(Temporal.PlainDate.from('2000-01-24')).toString();"; // Arity Error + String code = "Temporal.PlainDate.from('2000-01-24').equals(javaDate);"; + + java.time.LocalDate date = LocalDate.of(2000, 1, 24); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDate", date); + Value result = ctx.eval(ID, code); + assertTrue(result.asBoolean()); + } + } + + @Test + public void testPlainDateToString() { + String code = "javaDate.toString();"; + + java.time.LocalDate date = LocalDate.of(2000, 1, 24); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDate", date); + Value result = ctx.eval(ID, code); + Assert.assertEquals("2000-01-24", result.toString()); + } + } + + @Test + public void testPlainDateToLocaleString() { + String code = "javaDate.toLocaleString();"; + + java.time.LocalDate date = LocalDate.of(2000, 1, 24); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDate", date); + Value result = ctx.eval(ID, code); + Assert.assertEquals("2000-01-24", result.toString()); + } + } + + @Test + public void testPlainDateToJSON() { + String code = "javaDate.toJSON();"; + + java.time.LocalDate date = LocalDate.of(2000, 1, 24); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDate", date); + Value result = ctx.eval(ID, code); + Assert.assertEquals("2000-01-24", result.toString()); + } + } + + @Test(expected = RuntimeException.class) + public void testPlainDateValueOf() { + String code = "javaDate.valueOf();"; + + java.time.LocalDate date = LocalDate.of(2000, 1, 24); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDate", date); + Value result = ctx.eval(ID, code); + Assert.assertEquals("2000-01-24", result.toString()); + } + } + + @Test + public void testPlainDateToZonedDateTime() { + String code = "Temporal.PlainDate.from('2000-01-24').toZonedDateTime({ timeZone: 'America/Los_Angeles' }).toString();"; + + java.time.LocalDate date = LocalDate.of(2000, 1, 24); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDate", date); + Value result = ctx.eval(ID, code); + Assert.assertEquals("2000-01-24T00:00:00-08:00[America/Los_Angeles]", result.toString()); + } + } + + @Test + public void testPlainDateToPlainDateTime() { + String code = "javaDate.toPlainDateTime(Temporal.PlainTime.from('15:30:30')).toString();"; + + java.time.LocalDate date = LocalDate.of(2000, 1, 24); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDate", date); + Value result = ctx.eval(ID, code); + Assert.assertEquals("2000-01-24T15:30:30", result.toString()); + } + } + + @Test + public void testPlainDateToPlainYearMonth() { + String code = "javaDate.toPlainYearMonth().toString();"; + + java.time.LocalDate date = LocalDate.of(2000, 1, 24); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDate", date); + Value result = ctx.eval(ID, code); + Assert.assertEquals("2000-01", result.toString()); + } + } + + @Test + public void testPlainDateToPlainMonthDay() { + String code = "javaDate.toPlainMonthDay().toString();"; + + java.time.LocalDate date = LocalDate.of(2000, 1, 24); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDate", date); + Value result = ctx.eval(ID, code); + Assert.assertEquals("01-24", result.toString()); + } + } + + @Test + public void testPlainDateGetISOFields() { + String code = "javaDate.getISOFields().isoDay;"; + + java.time.LocalDate date = LocalDate.of(2000, 1, 24); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaDate", date); + Value result = ctx.eval(ID, code); + Assert.assertEquals("24", result.toString()); + } + } + + // ============================================================================================================== // + // Temporal TimeZone + // ============================================================================================================== // + + @Test + public void testTimeZoneGetOffsetNanosecondsFor() { + String code = "javaZone.getOffsetNanosecondsFor(Temporal.Instant.fromEpochSeconds(1_553_993_100));"; + + java.time.ZoneId zone = ZoneId.of("-08:00"); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaZone", zone); + Value result = ctx.eval(ID, code); + Assert.assertEquals(-28_800_000_000_000L, result.asLong()); + } + } + + @Test + public void testTimeZonegetOffsetStringFor() { + String code = "javaZone.getOffsetStringFor(Temporal.Instant.fromEpochSeconds(1_553_993_100));"; + + java.time.ZoneId zone = ZoneId.of("-08:00"); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaZone", zone); + Value result = ctx.eval(ID, code); + Assert.assertEquals("-08:00", result.toString()); + } + } + + @Test + public void testTimeZoneGetPlainDateTimeFor() { + String code = "javaZone.getPlainDateTimeFor(Temporal.Instant.fromEpochSeconds(1_553_993_100)).toString();"; + + java.time.ZoneId zone = ZoneId.of("Europe/Berlin"); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaZone", zone); + Value result = ctx.eval(ID, code); + Assert.assertEquals("2019-03-31T01:45:00", result.toString()); + } + } + + @Test + public void testTimeZoneGetInstantFor() { + String code = "javaZone.getInstantFor(Temporal.PlainDateTime.from('2019-03-31T01:45:00')).toString();"; + + java.time.ZoneId zone = ZoneId.of("Europe/Berlin"); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaZone", zone); + Value result = ctx.eval(ID, code); + Assert.assertEquals("2019-03-31T00:45:00Z", result.toString()); + } + } + + @Test + public void testTimeZoneGetPossibleInstantsFor() { + String code = "javaZone.getPossibleInstantsFor(Temporal.PlainDateTime.from('2019-03-31T01:45:00')).toString();"; + + java.time.ZoneId zone = ZoneId.of("Europe/Berlin"); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaZone", zone); + Value result = ctx.eval(ID, code); + Assert.assertEquals("2019-03-31T00:45:00Z", result.toString()); + } + } + + @Test + public void testTimeZoneGetNextTransition() { + String code = "javaZone.getNextTransition(Temporal.Instant.fromEpochSeconds(1_553_993_100)).toString();"; + + java.time.ZoneId zone = ZoneId.of("Europe/Berlin"); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaZone", zone); + Value result = ctx.eval(ID, code); + Assert.assertEquals("2019-03-31T01:00:00Z", result.toString()); + } + } + + @Test + public void testTimeZoneGetPreviousTransition() { + String code = "javaZone.getPreviousTransition(Temporal.Instant.fromEpochSeconds(1_553_993_100)).toString();"; + + java.time.ZoneId zone = ZoneId.of("Europe/Berlin"); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaZone", zone); + Value result = ctx.eval(ID, code); + Assert.assertEquals("2018-10-28T01:00:00Z", result.toString()); + } + } + + @Test + public void testTimeZoneToString() { + String code = "javaZone.toString();"; + + java.time.ZoneId zone = ZoneId.of("Europe/Berlin"); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaZone", zone); + Value result = ctx.eval(ID, code); + Assert.assertEquals("Europe/Berlin", result.toString()); + } + } + + @Test + public void testTimeZoneToJSON() { + String code = "javaZone.toJSON();"; + + java.time.ZoneId zone = ZoneId.of("Europe/Berlin"); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaZone", zone); + Value result = ctx.eval(ID, code); + Assert.assertEquals("Europe/Berlin", result.toString()); + } + } + + // ============================================================================================================== // + // Temporal PlainTime + // ============================================================================================================== // + + @Ignore // Unsupported operation identifier 'adjustInto' and object '{hours: 12}'(language: JavaScript, type: Object). Identifier is not executable or instantiable. + @Test + public void testPlainTimeWith() { + String code = "javaTime.with({hours: 12}).toString();"; + //String code = "Temporal.PlainTime.from('10:30:05').with({hours: 12}).toString();"; + + java.time.LocalTime time = LocalTime.of(10, 30, 5); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaTime", time); + Value result = ctx.eval(ID, code); + Assert.assertEquals("12:30:05", result.toString()); + } + } + + @Test + public void testPlainTimeAdd() { + String code = "javaTime.add({hours: 12}).toString();"; + //String code = "Temporal.PlainTime.from('10:30:05').add({hours: 12}).toString();"; + + java.time.LocalTime time = LocalTime.of(10, 30, 5); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaTime", time); + Value result = ctx.eval(ID, code); + Assert.assertEquals("22:30:05", result.toString()); + } + } + + @Test + public void testPlainTimeSubtract() { + String code = "javaTime.subtract({hours: 2}).toString();"; + //String code = "Temporal.PlainTime.from('10:30:05').subtract({hours: 2}).toString();"; + + java.time.LocalTime time = LocalTime.of(10, 30, 5); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaTime", time); + Value result = ctx.eval(ID, code); + Assert.assertEquals("08:30:05", result.toString()); + } + } + @Ignore // Arity Error + @Test + public void testPlainTimeUntil() { + String code = "javaTime.until(Temporal.PlainTime.from('11:00:00')).toString();"; + //String code = "Temporal.PlainTime.from('10:30:00').until(Temporal.PlainTime.from('11:00:00')).toString();"; + + java.time.LocalTime time = LocalTime.of(10, 30); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaTime", time); + Value result = ctx.eval(ID, code); + Assert.assertEquals("PT30M", result.toString()); + } + } + + @Test + public void testPlainTimeSince() { + String code = "javaTime.since(Temporal.PlainTime.from('10:00:00')).toString();"; + //String code = "Temporal.PlainTime.from('10:30:00').since(Temporal.PlainTime.from('10:00:00')).toString();"; + + java.time.LocalTime time = LocalTime.of(10, 30); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaTime", time); + Value result = ctx.eval(ID, code); + Assert.assertEquals("PT30M", result.toString()); + } + } + + @Test + public void testPlainTimeRound() { + String code = "javaTime.round({smallestUnit: 'hour'}).toString();"; + //String code = "Temporal.PlainTime.from('10:30:05').round({smallestUnit: 'hour'}).toString();"; + + java.time.LocalTime time = LocalTime.of(10, 30, 5); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaTime", time); + Value result = ctx.eval(ID, code); + Assert.assertEquals("11:00:00", result.toString()); + } + } + + @Test + public void testPlainTimeEquals() { + //String code = "javaTime.equals(Temporal.PlainTime.from('10:30:05'));"; + //String code = "Temporal.PlainTime.from('10:30:05').equals(Temporal.PlainTime.from('10:30:05'));"; + String code = "Temporal.PlainTime.from('10:30:05').equals(javaTime);"; + + java.time.LocalTime time = LocalTime.of(10, 30, 5); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaTime", time); + Value result = ctx.eval(ID, code); + Assert.assertEquals(true, result.asBoolean()); + } + } + + @Test + public void testPlainTimeToString() { + String code = "javaTime.toString();"; + //String code = "Temporal.PlainTime.from('10:30:05').toString();"; + + java.time.LocalTime time = LocalTime.of(10, 30, 5); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaTime", time); + Value result = ctx.eval(ID, code); + Assert.assertEquals("10:30:05", result.toString()); + } + } + + @Test + public void testPlainTimeToLocaleString() { + String code = "javaTime.toLocaleString();"; + //String code = "Temporal.PlainTime.from('10:30:05').toLocaleString();"; + + java.time.LocalTime time = LocalTime.of(10, 30, 5); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaTime", time); + Value result = ctx.eval(ID, code); + Assert.assertEquals("10:30:05", result.toString()); + } + } + + @Test + public void testPlainTimeToJSON() { + String code = "javaTime.toJSON();"; + //String code = "Temporal.PlainTime.from('10:30:05').toJSON();"; + + java.time.LocalTime time = LocalTime.of(10, 30, 5); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaTime", time); + Value result = ctx.eval(ID, code); + Assert.assertEquals("10:30:05", result.toString()); + } + } + + @Test(expected = RuntimeException.class) + public void testPlainTimeValueOf() { + String code = "javaTime.valueOf();"; + //String code = "Temporal.PlainTime.from('10:30:05').valueOf();"; + + java.time.LocalTime time = LocalTime.of(10, 30, 5); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaTime", time); + Value result = ctx.eval(ID, code); + Assert.assertEquals("10:30:05", result.toString()); + } + } + + @Test + public void testPlainTimeToZonedDateTime() { + String code = "javaTime.toZonedDateTime({ timeZone: 'America/Los_Angeles', plainDate: Temporal.PlainDate.from('2006-08-24') }).toString();"; + + java.time.LocalTime time = LocalTime.of(10, 30, 5); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaTime", time); + Value result = ctx.eval(ID, code); + Assert.assertEquals("2006-08-24T10:30:05-07:00[America/Los_Angeles]", result.toString()); + } + } + + @Test + public void testPlainTimeToPlainDateTime() { + String code = "javaTime.toPlainDateTime(Temporal.PlainDate.from('2000-01-01')).toString();"; + //String code = "Temporal.PlainTime.from('10:30:05').toPlainDateTime(Temporal.PlainDate.from('2000-01-01')).toString();"; + + java.time.LocalTime time = LocalTime.of(10, 30, 5); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaTime", time); + Value result = ctx.eval(ID, code); + Assert.assertEquals("2000-01-01T10:30:05", result.toString()); + } + } + + @Test + public void testPlainTimeGetISOFields() { + String code = "javaTime.getISOFields().isoHour;"; + //String code = "Temporal.PlainTime.from('10:30:05').getISOFields().isoHour;"; + + java.time.LocalTime time = LocalTime.of(10, 30, 5); + + try (Context ctx = Context.newBuilder("js").allowHostAccess(HostAccess.ALL).allowExperimentalOptions(true).// + option(JSContextOptions.FOREIGN_OBJECT_PROTOTYPE_NAME, "true").// + option(JSContextOptions.TEMPORAL_NAME, "true").build()) { + ctx.getBindings(ID).putMember("javaTime", time); + Value result = ctx.eval(ID, code); + Assert.assertEquals(10, result.asLong()); + } + } +} \ No newline at end of file diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ForeignObjectPrototypeTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ForeignObjectPrototypeTest.java index 77af09fa51c..4132aeab4a4 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ForeignObjectPrototypeTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ForeignObjectPrototypeTest.java @@ -46,14 +46,17 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import java.time.Instant; import java.util.Arrays; import java.util.List; +import com.oracle.truffle.js.runtime.JSContextOptions; import org.graalvm.polyglot.Context; import org.graalvm.polyglot.HostAccess; import org.graalvm.polyglot.Value; import org.graalvm.polyglot.proxy.ProxyArray; import org.graalvm.polyglot.proxy.ProxyExecutable; +import org.junit.Assert; import org.junit.Test; import com.oracle.truffle.js.test.JSTest; @@ -120,4 +123,16 @@ public void testHostMethodStatic() { } } -} + @Test + public void testJavaTimeInstant() { + try (Context context = JSTest.newContextBuilder(ID).option(FOREIGN_OBJECT_PROTOTYPE_NAME, "true").allowHostAccess(HostAccess.ALL).allowHostClassLookup(s -> true).build()) { + java.time.Instant inst = Instant.ofEpochMilli(100_000_000); + Value method = context.eval(ID, "( (inst) => { return inst; } );"); + assertTrue(method.canExecute()); + Value result = method.execute(inst); + assertTrue(result.isInstant()); + assertTrue(result.asInstant().equals(inst)); + } + } + +} \ No newline at end of file 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 d0deba6dece..b60a9a04e32 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 @@ -59,6 +59,7 @@ 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.profiles.ConditionProfile; import com.oracle.truffle.api.strings.TruffleString; @@ -101,6 +102,7 @@ import com.oracle.truffle.js.nodes.temporal.ToTemporalDurationNode; import com.oracle.truffle.js.runtime.Boundaries; import com.oracle.truffle.js.runtime.Errors; +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.Strings; @@ -232,6 +234,7 @@ protected Object createNode(JSContext context, JSBuiltin builtin, boolean constr return null; } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalCalendarGetterNode extends JSBuiltinNode { public final TemporalCalendarPrototype property; @@ -241,6 +244,7 @@ public JSTemporalCalendarGetterNode(JSContext context, JSBuiltin builtin, Tempor this.property = property; } + @CompilerDirectives.TruffleBoundary @Specialization(guards = "isJSTemporalCalendar(thisObj)") protected Object durationGetter(Object thisObj, @Cached JSToStringNode toStringNode) { 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 a2647884469..723989a76ea 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 @@ -56,11 +56,17 @@ import static com.oracle.truffle.js.runtime.util.TemporalUtil.dtol; import static com.oracle.truffle.js.runtime.util.TemporalUtil.getDouble; +import java.math.BigInteger; import java.util.EnumSet; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; 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.interop.UnsupportedMessageException; +import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.builtins.JSBuiltinsContainer; @@ -89,7 +95,9 @@ import com.oracle.truffle.js.nodes.temporal.TemporalUnbalanceDurationRelativeNode; import com.oracle.truffle.js.nodes.temporal.ToLimitedTemporalDurationNode; import com.oracle.truffle.js.nodes.temporal.ToRelativeTemporalObjectNode; +import com.oracle.truffle.js.runtime.BigInt; import com.oracle.truffle.js.runtime.Errors; +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.Strings; @@ -98,6 +106,8 @@ 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.JSTemporalPrecisionRecord; import com.oracle.truffle.js.runtime.objects.JSDynamicObject; import com.oracle.truffle.js.runtime.objects.Undefined; @@ -202,6 +212,7 @@ protected Object createNode(JSContext context, JSBuiltin builtin, boolean constr return null; } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalDurationGetterNode extends JSBuiltinNode { public final TemporalDurationPrototype property; @@ -211,6 +222,7 @@ public JSTemporalDurationGetterNode(JSContext context, JSBuiltin builtin, Tempor this.property = property; } + @TruffleBoundary @Specialization(guards = "isJSTemporalDuration(thisObj)") protected Object durationGetter(Object thisObj) { JSTemporalDurationObject temporalD = (JSTemporalDurationObject) thisObj; @@ -256,13 +268,43 @@ protected Object durationGetter(Object thisObj) { throw Errors.shouldNotReachHere(); } - @Specialization(guards = "!isJSTemporalDuration(thisObj)") - protected static int error(@SuppressWarnings("unused") Object thisObj) { + @Specialization(guards = "interop.isDuration(thisObj)") + protected Object instantGetterJavaDuration(@SuppressWarnings("unused") Object thisObj, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalDurationObject duration = javaDurationToDuration(thisObj, interop, getContext()); + return durationGetter(duration); + } + + @Specialization(guards = {"!isJSTemporalDuration(thisObj)", "!interop.isDuration(thisObj)"}) + protected static int error(@SuppressWarnings("unused") Object thisObj, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { throw TemporalErrors.createTypeErrorTemporalDurationExpected(); } + + @TruffleBoundary + public static JSTemporalDurationObject javaDurationToDuration(Object thisObj, InteropLibrary interop, JSContext context) { + try { + java.time.Duration duration = interop.asDuration(thisObj); + double days = duration.toDays(); + double years = 0; + double months = 0; + double weeks = 0; + double hours = Math.floor(duration.getSeconds() / 3_600) % 24; + double minutes = Math.floor(duration.getSeconds() / 60) % 60; + double seconds = duration.getSeconds() % 60; + double milliseconds = Math.floor(duration.getNano() / 1_000_000) % 1_000; + double microseconds = Math.floor(duration.getNano() / 1_000) % 1_000; + double nanoseconds = duration.getNano() % 1_000; + + return JSTemporalDuration.createTemporalDuration(context, years, months, weeks, days, hours, minutes, seconds, milliseconds, microseconds, nanoseconds); + } catch (UnsupportedMessageException e) { + return null; + } + } } // 7.3.15 + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalDurationWith extends JSTemporalBuiltinOperation { protected JSTemporalDurationWith(JSContext context, JSBuiltin builtin) { @@ -271,8 +313,9 @@ protected JSTemporalDurationWith(JSContext context, JSBuiltin builtin) { @Specialization protected JSDynamicObject with(Object thisObj, Object temporalDurationLike, - @Cached("create()") JSToIntegerWithoutRoundingNode toInt) { - JSTemporalDurationObject duration = requireTemporalDuration(thisObj); + @Cached("create()") JSToIntegerWithoutRoundingNode toInt, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalDurationObject duration = requireTemporalDuration(thisObj, interop, getContext()); JSDynamicObject durationLike = TemporalUtil.toPartialDuration(temporalDurationLike, getContext(), isObjectNode, toInt, errorBranch); @@ -292,6 +335,7 @@ protected JSDynamicObject with(Object thisObj, Object temporalDurationLike, } // 7.3.16 + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalDurationNegated extends JSTemporalBuiltinOperation { protected JSTemporalDurationNegated(JSContext context, JSBuiltin builtin) { @@ -299,8 +343,9 @@ protected JSTemporalDurationNegated(JSContext context, JSBuiltin builtin) { } @Specialization - protected JSDynamicObject negated(Object thisObj) { - JSTemporalDurationObject duration = requireTemporalDuration(thisObj); + protected JSDynamicObject negated(Object thisObj, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalDurationObject duration = requireTemporalDuration(thisObj, interop, getContext()); return JSTemporalDuration.createTemporalDuration(getContext(), -duration.getYears(), -duration.getMonths(), -duration.getWeeks(), -duration.getDays(), -duration.getHours(), -duration.getMinutes(), -duration.getSeconds(), -duration.getMilliseconds(), @@ -309,6 +354,7 @@ protected JSDynamicObject negated(Object thisObj) { } // 7.3.17 + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalDurationAbs extends JSTemporalBuiltinOperation { protected JSTemporalDurationAbs(JSContext context, JSBuiltin builtin) { @@ -316,8 +362,9 @@ protected JSTemporalDurationAbs(JSContext context, JSBuiltin builtin) { } @Specialization - protected JSDynamicObject abs(Object thisObj) { - JSTemporalDurationObject duration = requireTemporalDuration(thisObj); + protected JSDynamicObject abs(Object thisObj, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalDurationObject duration = requireTemporalDuration(thisObj, interop, getContext()); return JSTemporalDuration.createTemporalDuration(getContext(), Math.abs(duration.getYears()), Math.abs(duration.getMonths()), Math.abs(duration.getWeeks()), Math.abs(duration.getDays()), Math.abs(duration.getHours()), Math.abs(duration.getMinutes()), @@ -327,6 +374,7 @@ protected JSDynamicObject abs(Object thisObj) { } // 7.3.18 + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalDurationAdd extends JSTemporalBuiltinOperation { protected JSTemporalDurationAdd(JSContext context, JSBuiltin builtin) { @@ -337,9 +385,10 @@ protected JSTemporalDurationAdd(JSContext context, JSBuiltin builtin) { protected JSDynamicObject add(Object thisObj, Object other, Object options, @Cached("create(getContext())") TemporalDurationAddNode durationAddNode, @Cached("create(getContext())") ToRelativeTemporalObjectNode toRelativeTemporalObjectNode, - @Cached("create()") ToLimitedTemporalDurationNode toLimitedTemporalDurationNode) { - JSTemporalDurationObject duration = requireTemporalDuration(thisObj); - JSTemporalDurationRecord otherDuration = toLimitedTemporalDurationNode.executeDynamicObject(other, TemporalUtil.listEmpty); + @Cached("create()") ToLimitedTemporalDurationNode toLimitedTemporalDurationNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalDurationObject duration = requireTemporalDuration(thisObj, interop, getContext()); + JSTemporalDurationRecord otherDuration = toLimitedTemporalDurationNode.executeDynamicObject(convertJavaToJavascriptDuration(other, interop, getContext()), TemporalUtil.listEmpty); JSDynamicObject normalizedOptions = getOptionsObject(options); JSDynamicObject relativeTo = toRelativeTemporalObjectNode.execute(normalizedOptions); JSTemporalDurationRecord result = durationAddNode.execute(duration.getYears(), duration.getMonths(), @@ -357,6 +406,7 @@ protected JSDynamicObject add(Object thisObj, Object other, Object options, } // 7.3.19 + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalDurationSubtract extends JSTemporalBuiltinOperation { protected JSTemporalDurationSubtract(JSContext context, JSBuiltin builtin) { @@ -367,9 +417,10 @@ protected JSTemporalDurationSubtract(JSContext context, JSBuiltin builtin) { protected JSDynamicObject subtract(Object thisObj, Object other, Object options, @Cached("create(getContext())") TemporalDurationAddNode durationAddNode, @Cached("create(getContext())") ToRelativeTemporalObjectNode toRelativeTemporalObjectNode, - @Cached("create()") ToLimitedTemporalDurationNode toLimitedTemporalDurationNode) { - JSTemporalDurationObject duration = requireTemporalDuration(thisObj); - JSTemporalDurationRecord otherDuration = toLimitedTemporalDurationNode.executeDynamicObject(other, TemporalUtil.listEmpty); + @Cached("create()") ToLimitedTemporalDurationNode toLimitedTemporalDurationNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalDurationObject duration = requireTemporalDuration(thisObj, interop, getContext()); + JSTemporalDurationRecord otherDuration = toLimitedTemporalDurationNode.executeDynamicObject(convertJavaToJavascriptDuration(other, interop, getContext()), TemporalUtil.listEmpty); JSDynamicObject normalizedOptions = getOptionsObject(options); JSDynamicObject relativeTo = toRelativeTemporalObjectNode.execute(normalizedOptions); JSTemporalDurationRecord result = durationAddNode.execute(duration.getYears(), duration.getMonths(), @@ -386,6 +437,7 @@ protected JSDynamicObject subtract(Object thisObj, Object other, Object options, } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalDurationRound extends JSTemporalBuiltinOperation { protected JSTemporalDurationRound(JSContext context, JSBuiltin builtin) { @@ -404,8 +456,9 @@ protected JSDynamicObject round(Object thisObj, Object roundToParam, @Cached("create(getContext())") ToRelativeTemporalObjectNode toRelativeTemporalObjectNode, @Cached("create(getContext())") TemporalRoundDurationNode roundDurationNode, @Cached("create(getContext())") TemporalUnbalanceDurationRelativeNode unbalanceDurationRelativeNode, - @Cached("create(getContext())") TemporalBalanceDurationRelativeNode balanceDurationRelativeNode) { - JSTemporalDurationObject duration = requireTemporalDuration(thisObj); + @Cached("create(getContext())") TemporalBalanceDurationRelativeNode balanceDurationRelativeNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalDurationObject duration = requireTemporalDuration(thisObj, interop, getContext()); if (roundToParam == Undefined.instance) { throw TemporalErrors.createTypeErrorOptionsUndefined(); } @@ -471,6 +524,7 @@ protected JSDynamicObject round(Object thisObj, Object roundToParam, } // 7.3.21 + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalDurationTotal extends JSTemporalBuiltinOperation { protected JSTemporalDurationTotal(JSContext context, JSBuiltin builtin) { @@ -484,8 +538,9 @@ protected double total(Object thisObj, Object totalOfParam, @Cached TruffleString.EqualNode equalNode, @Cached("create(getContext())") ToRelativeTemporalObjectNode toRelativeTemporalObjectNode, @Cached("create(getContext())") TemporalRoundDurationNode roundDurationNode, - @Cached("create(getContext())") TemporalUnbalanceDurationRelativeNode unbalanceDurationRelativeNode) { - JSTemporalDurationObject duration = requireTemporalDuration(thisObj); + @Cached("create(getContext())") TemporalUnbalanceDurationRelativeNode unbalanceDurationRelativeNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalDurationObject duration = requireTemporalDuration(thisObj, interop, getContext()); if (totalOfParam == Undefined.instance) { errorBranch.enter(); throw TemporalErrors.createTypeErrorOptionsUndefined(); @@ -538,6 +593,7 @@ protected double total(Object thisObj, Object totalOfParam, } // 7.3.23 & 7.3.24 + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalDurationToLocaleString extends JSTemporalBuiltinOperation { protected JSTemporalDurationToLocaleString(JSContext context, JSBuiltin builtin) { @@ -546,8 +602,9 @@ protected JSTemporalDurationToLocaleString(JSContext context, JSBuiltin builtin) @Specialization protected TruffleString toString(Object thisObj, - @Cached JSNumberToBigIntNode toBigIntNode) { - JSTemporalDurationObject duration = requireTemporalDuration(thisObj); + @Cached JSNumberToBigIntNode toBigIntNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalDurationObject duration = requireTemporalDuration(thisObj, interop, getContext()); return JSTemporalDuration.temporalDurationToString( dtol(duration.getYears()), dtol(duration.getMonths()), dtol(duration.getWeeks()), dtol(duration.getDays()), dtol(duration.getHours()), dtol(duration.getMinutes()), dtol(duration.getSeconds()), @@ -556,6 +613,7 @@ protected TruffleString toString(Object thisObj, } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalDurationToString extends JSTemporalBuiltinOperation { protected JSTemporalDurationToString(JSContext context, JSBuiltin builtin) { @@ -567,8 +625,9 @@ protected TruffleString toString(Object duration, Object opt, @Cached JSNumberToBigIntNode toBigIntNode, @Cached JSToStringNode toStringNode, @Cached TruffleString.EqualNode equalNode, - @Cached("create(getContext())") TemporalRoundDurationNode roundDurationNode) { - JSTemporalDurationObject dur = requireTemporalDuration(duration); + @Cached("create(getContext())") TemporalRoundDurationNode roundDurationNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalDurationObject dur = requireTemporalDuration(duration, interop, getContext()); JSDynamicObject options = getOptionsObject(opt); JSTemporalPrecisionRecord precision = TemporalUtil.toSecondsStringPrecision(options, toStringNode, getOptionNode(), equalNode); if (precision.getUnit() == Unit.MINUTE) { @@ -587,6 +646,7 @@ protected TruffleString toString(Object duration, Object opt, } // 7.3.26 + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalDurationValueOf extends JSTemporalBuiltinOperation { protected JSTemporalDurationValueOf(JSContext context, JSBuiltin builtin) { 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 45e9cfc5a0e..0ffcd6ec570 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 @@ -52,7 +52,11 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; 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.interop.UnsupportedMessageException; +import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.builtins.JSBuiltinsContainer; import com.oracle.truffle.js.builtins.temporal.TemporalInstantPrototypeBuiltinsFactory.JSTemporalInstantAddNodeGen; @@ -78,6 +82,7 @@ import com.oracle.truffle.js.nodes.temporal.ToTemporalTimeZoneNode; import com.oracle.truffle.js.runtime.BigInt; import com.oracle.truffle.js.runtime.Errors; +import com.oracle.truffle.js.runtime.JSConfig; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRealm; import com.oracle.truffle.js.runtime.JSRuntime; @@ -182,6 +187,7 @@ protected Object createNode(JSContext context, JSBuiltin builtin, boolean constr return null; } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalInstantGetterNode extends JSBuiltinNode { public final TemporalInstantPrototype property; @@ -211,13 +217,35 @@ protected Object instantGetter(Object thisObj) { throw Errors.shouldNotReachHere(); } - @Specialization(guards = "!isJSTemporalInstant(thisObj)") - protected static int error(@SuppressWarnings("unused") Object thisObj) { + @Specialization(guards = "interop.isInstant(thisObj)") + protected Object instantGetterJavaInstant(@SuppressWarnings("unused") Object thisObj, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalInstantObject instant = javaInstantToInstant(thisObj, interop, getContext()); + return instantGetter(instant); + } + + @Specialization(guards = {"!isJSTemporalInstant(thisObj)", "!interop.isInstant(thisObj)"}) + protected static int error(@SuppressWarnings("unused") Object thisObj, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { throw TemporalErrors.createTypeErrorTemporalInstantExpected(); } + + @TruffleBoundary + public static JSTemporalInstantObject javaInstantToInstant(Object thisObj, InteropLibrary interop, JSContext context) { + try { + java.time.Instant instant = interop.asInstant(thisObj); + BigInteger bi = BigInteger.valueOf(instant.getEpochSecond()); + bi = bi.multiply(BigInteger.valueOf(1_000_000_000)); + bi = bi.add(BigInteger.valueOf(instant.getNano())); + return JSTemporalInstant.create(context, new BigInt(bi)); + } catch (UnsupportedMessageException e) { + return null; + } + } } - // 4.3.10 + // 4.3.10\ + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalInstantAdd extends JSTemporalBuiltinOperation { protected JSTemporalInstantAdd(JSContext context, JSBuiltin builtin) { @@ -226,15 +254,17 @@ protected JSTemporalInstantAdd(JSContext context, JSBuiltin builtin) { @Specialization public JSDynamicObject add(Object thisObj, Object temporalDurationLike, - @Cached("create()") ToLimitedTemporalDurationNode toLimitedTemporalDurationNode) { - JSTemporalInstantObject instant = requireTemporalInstant(thisObj); + @Cached("create()") ToLimitedTemporalDurationNode toLimitedTemporalDurationNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalInstantObject instant = requireTemporalInstant(thisObj, interop, getContext()); JSTemporalDurationRecord duration = toLimitedTemporalDurationNode.executeDynamicObject(temporalDurationLike, TemporalUtil.listPluralYMWD); BigInt ns = TemporalUtil.addInstant(instant.getNanoseconds(), duration.getHours(), duration.getMinutes(), duration.getSeconds(), - duration.getMilliseconds(), duration.getMicroseconds(), duration.getNanoseconds()); + duration.getMilliseconds(), duration.getMicroseconds(), duration.getNanoseconds()); return JSTemporalInstant.create(getContext(), getRealm(), ns); } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalInstantSubtract extends JSTemporalBuiltinOperation { protected JSTemporalInstantSubtract(JSContext context, JSBuiltin builtin) { @@ -243,15 +273,17 @@ protected JSTemporalInstantSubtract(JSContext context, JSBuiltin builtin) { @Specialization public JSDynamicObject subtract(Object thisObj, Object temporalDurationLike, - @Cached("create()") ToLimitedTemporalDurationNode toLimitedTemporalDurationNode) { - JSTemporalInstantObject instant = requireTemporalInstant(thisObj); + @Cached("create()") ToLimitedTemporalDurationNode toLimitedTemporalDurationNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalInstantObject instant = requireTemporalInstant(thisObj, interop, getContext()); JSTemporalDurationRecord duration = toLimitedTemporalDurationNode.executeDynamicObject(temporalDurationLike, TemporalUtil.listPluralYMWD); BigInt ns = TemporalUtil.addInstant(instant.getNanoseconds(), -duration.getHours(), -duration.getMinutes(), -duration.getSeconds(), - -duration.getMilliseconds(), -duration.getMicroseconds(), -duration.getNanoseconds()); + -duration.getMilliseconds(), -duration.getMicroseconds(), -duration.getNanoseconds()); return JSTemporalInstant.create(getContext(), getRealm(), ns); } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalInstantUntilSinceNode extends JSTemporalBuiltinOperation { private final boolean isUntil; @@ -263,12 +295,13 @@ protected JSTemporalInstantUntilSinceNode(JSContext context, JSBuiltin builtin, @Specialization public JSDynamicObject untilOrSince(Object thisObj, Object otherObj, Object optionsParam, - @Cached("create()") JSToNumberNode toNumber, - @Cached("createKeys(getContext())") EnumerableOwnPropertyNamesNode namesNode, - @Cached TruffleString.EqualNode equalNode, - @Cached("create(getContext())") ToTemporalInstantNode toTemporalInstantNode) { - JSTemporalInstantObject instant = requireTemporalInstant(thisObj); - JSTemporalInstantObject other = toTemporalInstantNode.execute(otherObj); + @Cached("create()") JSToNumberNode toNumber, + @Cached("createKeys(getContext())") EnumerableOwnPropertyNamesNode namesNode, + @Cached TruffleString.EqualNode equalNode, + @Cached("create(getContext())") ToTemporalInstantNode toTemporalInstantNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalInstantObject instant = requireTemporalInstant(thisObj, interop, getContext()); + JSTemporalInstantObject other = toTemporalInstantNode.execute(convertJavaToJavascriptInstant(otherObj, interop, getContext())); JSDynamicObject options = getOptionsObject(optionsParam); Unit smallestUnit = toSmallestTemporalUnit(options, TemporalUtil.listYMWD, NANOSECOND, equalNode); Unit defaultLargestUnit = TemporalUtil.largerOfTwoTemporalUnits(Unit.SECOND, smallestUnit); @@ -284,10 +317,11 @@ public JSDynamicObject untilOrSince(Object thisObj, Object otherObj, Object opti BigInteger roundedNs = TemporalUtil.differenceInstant(one, two, roundingIncrement, smallestUnit, roundingMode); JSTemporalDurationRecord result = TemporalUtil.balanceDuration(getContext(), namesNode, 0, 0, 0, 0, 0, 0, roundedNs, largestUnit, Undefined.instance); return JSTemporalDuration.createTemporalDuration(getContext(), 0, 0, 0, 0, result.getHours(), result.getMinutes(), result.getSeconds(), - result.getMilliseconds(), result.getMicroseconds(), result.getNanoseconds(), errorBranch); + result.getMilliseconds(), result.getMicroseconds(), result.getNanoseconds(), errorBranch); } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalInstantRound extends JSTemporalBuiltinOperation { protected JSTemporalInstantRound(JSContext context, JSBuiltin builtin) { @@ -296,9 +330,10 @@ protected JSTemporalInstantRound(JSContext context, JSBuiltin builtin) { @Specialization public JSDynamicObject round(Object thisObj, Object roundToParam, - @Cached("create()") JSToNumberNode toNumber, - @Cached TruffleString.EqualNode equalNode) { - JSTemporalInstantObject instant = requireTemporalInstant(thisObj); + @Cached("create()") JSToNumberNode toNumber, + @Cached TruffleString.EqualNode equalNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalInstantObject instant = requireTemporalInstant(thisObj, interop, getContext()); if (roundToParam == Undefined.instance) { throw TemporalErrors.createTypeErrorOptionsUndefined(); } @@ -336,6 +371,7 @@ public JSDynamicObject round(Object thisObj, Object roundToParam, } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalInstantEquals extends JSTemporalBuiltinOperation { protected JSTemporalInstantEquals(JSContext context, JSBuiltin builtin) { @@ -344,13 +380,15 @@ protected JSTemporalInstantEquals(JSContext context, JSBuiltin builtin) { @Specialization public boolean equals(Object thisObj, Object otherObj, - @Cached("create(getContext())") ToTemporalInstantNode toTemporalInstantNode) { - JSTemporalInstantObject instant = requireTemporalInstant(thisObj); - JSTemporalInstantObject other = toTemporalInstantNode.execute(otherObj); + @Cached("create(getContext())") ToTemporalInstantNode toTemporalInstantNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalInstantObject instant = requireTemporalInstant(thisObj, interop, getContext()); + JSTemporalInstantObject other = toTemporalInstantNode.execute(convertJavaToJavascriptInstant(otherObj, interop, getContext())); return instant.getNanoseconds().compareTo(other.getNanoseconds()) == 0; } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalInstantToString extends JSTemporalBuiltinOperation { protected JSTemporalInstantToString(JSContext context, JSBuiltin builtin) { @@ -359,10 +397,11 @@ protected JSTemporalInstantToString(JSContext context, JSBuiltin builtin) { @Specialization protected TruffleString toString(Object thisObj, Object optionsParam, - @Cached("create(getContext())") ToTemporalTimeZoneNode toTemporalTimeZone, - @Cached JSToStringNode toStringNode, - @Cached TruffleString.EqualNode equalNode) { - JSTemporalInstantObject instant = requireTemporalInstant(thisObj); + @Cached("create(getContext())") ToTemporalTimeZoneNode toTemporalTimeZone, + @Cached JSToStringNode toStringNode, + @Cached TruffleString.EqualNode equalNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalInstantObject instant = requireTemporalInstant(thisObj, interop, getContext()); JSDynamicObject options = getOptionsObject(optionsParam); Object timeZoneRaw = JSObject.get(options, TIME_ZONE); JSDynamicObject timeZone = Undefined.instance; @@ -379,6 +418,7 @@ protected TruffleString toString(Object thisObj, Object optionsParam, } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalInstantToLocaleString extends JSTemporalBuiltinOperation { protected JSTemporalInstantToLocaleString(JSContext context, JSBuiltin builtin) { @@ -393,6 +433,7 @@ public TruffleString toLocaleString(Object thisObj) { } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalInstantValueOf extends JSTemporalBuiltinOperation { protected JSTemporalInstantValueOf(JSContext context, JSBuiltin builtin) { @@ -405,6 +446,7 @@ protected Object valueOf(@SuppressWarnings("unused") Object thisObj) { } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalInstantToZonedDateTimeNode extends JSTemporalBuiltinOperation { protected JSTemporalInstantToZonedDateTimeNode(JSContext context, JSBuiltin builtin) { @@ -413,9 +455,10 @@ protected JSTemporalInstantToZonedDateTimeNode(JSContext context, JSBuiltin buil @Specialization protected JSDynamicObject toZonedDateTime(Object thisObj, Object item, - @Cached("create(getContext())") ToTemporalCalendarNode toTemporalCalendar, - @Cached("create(getContext())") ToTemporalTimeZoneNode toTemporalTimeZone) { - JSTemporalInstantObject instant = requireTemporalInstant(thisObj); + @Cached("create(getContext())") ToTemporalCalendarNode toTemporalCalendar, + @Cached("create(getContext())") ToTemporalTimeZoneNode toTemporalTimeZone, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalInstantObject instant = requireTemporalInstant(thisObj, interop, getContext()); if (!isObject(item)) { errorBranch.enter(); throw Errors.createTypeError("object expected"); @@ -437,6 +480,7 @@ protected JSDynamicObject toZonedDateTime(Object thisObj, Object item, } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalInstantToZonedDateTimeISONode extends JSTemporalBuiltinOperation { protected JSTemporalInstantToZonedDateTimeISONode(JSContext context, JSBuiltin builtin) { @@ -445,8 +489,9 @@ protected JSTemporalInstantToZonedDateTimeISONode(JSContext context, JSBuiltin b @Specialization protected Object toZonedDateTimeISO(Object thisObj, Object itemParam, - @Cached("create(getContext())") ToTemporalTimeZoneNode toTemporalTimeZone) { - JSTemporalInstantObject instant = requireTemporalInstant(thisObj); + @Cached("create(getContext())") ToTemporalTimeZoneNode toTemporalTimeZone, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalInstantObject instant = requireTemporalInstant(thisObj, interop, getContext()); Object item = itemParam; if (isObject(item)) { JSDynamicObject itemObj = TemporalUtil.toJSDynamicObject(item, errorBranch); @@ -462,4 +507,4 @@ protected Object toZonedDateTimeISO(Object thisObj, Object itemParam, } } -} +} \ No newline at end of file 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 d3d6340493f..b1eb3901d6f 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 @@ -50,15 +50,21 @@ import static com.oracle.truffle.js.runtime.util.TemporalConstants.TRUNC; import static com.oracle.truffle.js.runtime.util.TemporalConstants.UNIT; +import java.time.LocalDate; import java.util.EnumSet; import java.util.List; import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.Truffle; 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.UnsupportedMessageException; +import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.strings.TruffleString; +import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.js.builtins.JSBuiltinsContainer; import com.oracle.truffle.js.builtins.temporal.TemporalPlainDatePrototypeBuiltinsFactory.JSTemporalPlainDateAddNodeGen; import com.oracle.truffle.js.builtins.temporal.TemporalPlainDatePrototypeBuiltinsFactory.JSTemporalPlainDateEqualsNodeGen; @@ -96,9 +102,12 @@ import com.oracle.truffle.js.nodes.temporal.ToTemporalTimeZoneNode; import com.oracle.truffle.js.runtime.Boundaries; import com.oracle.truffle.js.runtime.Errors; +import com.oracle.truffle.js.runtime.JSConfig; 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.JSOrdinary; +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.JSTemporalDuration; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalDurationObject; @@ -109,6 +118,7 @@ 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.JSTemporalPlainMonthDayObject; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainTime; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainTimeObject; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainYearMonthObject; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalTimeZoneObject; @@ -240,6 +250,7 @@ protected Object createNode(JSContext context, JSBuiltin builtin, boolean constr return null; } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainDateGetterNode extends JSBuiltinNode { public final TemporalPlainDatePrototype property; @@ -249,6 +260,7 @@ public JSTemporalPlainDateGetterNode(JSContext context, JSBuiltin builtin, Tempo this.property = property; } + @CompilerDirectives.TruffleBoundary @Specialization(guards = "isJSTemporalDate(thisObj)") protected Object dateGetter(Object thisObj, @Cached("create(getContext())") TemporalCalendarGetterNode calendarGetterNode) { @@ -285,10 +297,27 @@ protected Object dateGetter(Object thisObj, throw Errors.shouldNotReachHere(); } - @Specialization(guards = "!isJSTemporalDate(thisObj)") - protected static int error(@SuppressWarnings("unused") Object thisObj) { + @Specialization(guards = {"!isJSTemporalDate(thisObj)", "!interop.isDate(thisObj)"}) + protected static int error(@SuppressWarnings("unused") Object thisObj, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { throw TemporalErrors.createTypeErrorTemporalDateExpected(); } + + // TODO + @CompilerDirectives.TruffleBoundary + public static JSTemporalPlainDateObject javaPlainDateToPlainDate(Object thisObj, InteropLibrary interop, JSContext context, JSRealm realm) { + try { + java.time.LocalDate date = interop.asDate(thisObj); + int year = date.getYear(); + int month = date.getMonthValue(); + int day = date.getDayOfMonth(); + JSDynamicObject calender = TemporalUtil.getISO8601Calendar(context, realm); + + return JSTemporalPlainDate.create(context, year, month, day, calender); + } catch (UnsupportedMessageException e) { + return null; + } + } } /** @@ -313,6 +342,26 @@ protected JSTemporalPlainDateObject requireTemporalDate(Object obj) { return (JSTemporalPlainDateObject) obj; } + protected JSTemporalPlainDateObject requireTemporalDate(Object obj, InteropLibrary interop, JSContext ctx) { + if (obj instanceof JSTemporalPlainDateObject) { + return (JSTemporalPlainDateObject) obj; + } + if (interop.isDate(obj)) { + JSTemporalPlainDateObject date = TemporalPlainDatePrototypeBuiltins.JSTemporalPlainDateGetterNode.javaPlainDateToPlainDate(obj, interop, ctx, getRealm()); + return date; + } + errorBranch.enter(); + throw TemporalErrors.createTypeErrorTemporalDateExpected(); + } + + protected JSTemporalPlainDateObject convertJavaToJavascriptPlainDate(Object obj, InteropLibrary interop, JSContext ctx) { + if (interop.isDate(obj)) { + JSTemporalPlainDateObject date = TemporalPlainDatePrototypeBuiltins.JSTemporalPlainDateGetterNode.javaPlainDateToPlainDate(obj, interop, ctx, getRealm()); + return date; + } + return (JSTemporalPlainDateObject) obj; + } + protected TemporalTime requireTemporalTime(Object obj) { if (!(obj instanceof TemporalTime)) { errorBranch.enter(); @@ -321,6 +370,26 @@ protected TemporalTime requireTemporalTime(Object obj) { return (TemporalTime) obj; } + protected JSTemporalPlainTimeObject requireTemporalTime(Object obj, InteropLibrary interop, JSContext ctx) { + if (obj instanceof JSTemporalPlainTimeObject) { + return (JSTemporalPlainTimeObject) obj; + } + if (interop.isTime(obj)) { + JSTemporalPlainTimeObject time = TemporalPlainTimePrototypeBuiltins.JSTemporalPlainTimeGetterNode.javaPlainTimeToPlainTime(obj, interop, ctx, errorBranch); + return time; + } + errorBranch.enter(); + throw TemporalErrors.createTypeErrorTemporalTimeExpected(); + } + + protected JSTemporalPlainTimeObject convertJavaToJavascriptPlainTime(Object obj, InteropLibrary interop, JSContext ctx) { + if (interop.isTime(obj)) { + JSTemporalPlainTimeObject time = TemporalPlainTimePrototypeBuiltins.JSTemporalPlainTimeGetterNode.javaPlainTimeToPlainTime(obj, interop, ctx, errorBranch); + return time; + } + return (JSTemporalPlainTimeObject) obj; + } + protected JSTemporalPlainDateTimeObject requireTemporalDateTime(Object obj) { if (!(obj instanceof JSTemporalPlainDateTimeObject)) { errorBranch.enter(); @@ -353,6 +422,26 @@ protected JSTemporalInstantObject requireTemporalInstant(Object obj) { return (JSTemporalInstantObject) obj; } + protected JSTemporalInstantObject requireTemporalInstant(Object obj, InteropLibrary interop, JSContext ctx) { + if (obj instanceof JSTemporalInstantObject) { + return (JSTemporalInstantObject) obj; + } + if (interop.isInstant(obj)) { + JSTemporalInstantObject inst = TemporalInstantPrototypeBuiltins.JSTemporalInstantGetterNode.javaInstantToInstant(obj, interop, ctx); + return inst; + } + errorBranch.enter(); + throw TemporalErrors.createTypeErrorTemporalInstantExpected(); + } + + protected JSTemporalInstantObject convertJavaToJavascriptInstant(Object obj, InteropLibrary interop, JSContext ctx) { + if (interop.isInstant(obj)) { + JSTemporalInstantObject inst = TemporalInstantPrototypeBuiltins.JSTemporalInstantGetterNode.javaInstantToInstant(obj, interop, ctx); + return inst; + } + return (JSTemporalInstantObject) obj; + } + protected JSTemporalZonedDateTimeObject requireTemporalZonedDateTime(Object obj) { if (!(obj instanceof JSTemporalZonedDateTimeObject)) { errorBranch.enter(); @@ -377,6 +466,26 @@ protected JSTemporalDurationObject requireTemporalDuration(Object obj) { return (JSTemporalDurationObject) obj; } + protected JSTemporalDurationObject requireTemporalDuration(Object obj, InteropLibrary interop, JSContext ctx) { + if (obj instanceof JSTemporalDurationObject) { + return (JSTemporalDurationObject) obj; + } + if (interop.isDuration(obj)) { + JSTemporalDurationObject dur = TemporalDurationPrototypeBuiltins.JSTemporalDurationGetterNode.javaDurationToDuration(obj, interop, ctx); + return dur; + } + errorBranch.enter(); + throw TemporalErrors.createTypeErrorTemporalDurationExpected(); + } + + protected Object convertJavaToJavascriptDuration(Object obj, InteropLibrary interop, JSContext ctx) { + if (interop.isDuration(obj)) { + JSTemporalDurationObject dur = TemporalDurationPrototypeBuiltins.JSTemporalDurationGetterNode.javaDurationToDuration(obj, interop, ctx); + return dur; + } + return obj; + } + protected JSTemporalTimeZoneObject requireTemporalTimeZone(Object obj) { if (!(obj instanceof JSTemporalTimeZoneObject)) { errorBranch.enter(); @@ -385,6 +494,18 @@ protected JSTemporalTimeZoneObject requireTemporalTimeZone(Object obj) { return (JSTemporalTimeZoneObject) obj; } + protected JSTemporalTimeZoneObject requireTemporalTimeZone(Object obj, InteropLibrary interop, JSContext ctx) { + if (obj instanceof JSTemporalTimeZoneObject) { + return (JSTemporalTimeZoneObject) obj; + } + if (interop.isTimeZone(obj)) { + JSTemporalTimeZoneObject zone = TemporalTimeZonePrototypeBuiltins.JSTemporalTimeZoneGetterNode.javaTimeZoneToTimeZone(obj, interop, ctx); + return zone; + } + errorBranch.enter(); + throw TemporalErrors.createTypeErrorTemporalTimeZoneExpected(); + } + protected JSDynamicObject getOptionsObject(Object options) { if (optionUndefined.profile(options == Undefined.instance)) { return JSOrdinary.createWithNullPrototype(getContext()); @@ -454,6 +575,7 @@ protected TemporalGetOptionNode getOptionNode() { } // 4.3.10 + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainDateAdd extends JSTemporalBuiltinOperation { protected JSTemporalPlainDateAdd(JSContext context, JSBuiltin builtin) { @@ -463,8 +585,9 @@ protected JSTemporalPlainDateAdd(JSContext context, JSBuiltin builtin) { @Specialization public JSDynamicObject add(Object thisObj, Object temporalDurationLike, Object optParam, @Cached("createKeys(getContext())") EnumerableOwnPropertyNamesNode namesNode, - @Cached("create()") ToLimitedTemporalDurationNode toLimitedTemporalDurationNode) { - JSTemporalPlainDateObject date = requireTemporalDate(thisObj); + @Cached("create()") ToLimitedTemporalDurationNode toLimitedTemporalDurationNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalPlainDateObject date = requireTemporalDate(thisObj, interop, getContext()); JSTemporalDurationRecord duration = toLimitedTemporalDurationNode.executeDynamicObject(temporalDurationLike, TemporalUtil.listEmpty); JSDynamicObject options = getOptionsObject(optParam); JSTemporalDurationRecord balanceResult = TemporalUtil.balanceDuration(getContext(), namesNode, @@ -476,6 +599,7 @@ public JSDynamicObject add(Object thisObj, Object temporalDurationLike, Object o } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainDateSubtract extends JSTemporalBuiltinOperation { protected JSTemporalPlainDateSubtract(JSContext context, JSBuiltin builtin) { @@ -485,8 +609,9 @@ protected JSTemporalPlainDateSubtract(JSContext context, JSBuiltin builtin) { @Specialization public JSDynamicObject subtract(Object thisObj, Object temporalDurationLike, Object optParam, @Cached("createKeys(getContext())") EnumerableOwnPropertyNamesNode namesNode, - @Cached("create()") ToLimitedTemporalDurationNode toLimitedTemporalDurationNode) { - JSTemporalPlainDateObject date = requireTemporalDate(thisObj); + @Cached("create()") ToLimitedTemporalDurationNode toLimitedTemporalDurationNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalPlainDateObject date = requireTemporalDate(thisObj, interop, getContext()); JSTemporalDurationRecord duration = toLimitedTemporalDurationNode.executeDynamicObject(temporalDurationLike, TemporalUtil.listEmpty); JSDynamicObject options = getOptionsObject(optParam); JSTemporalDurationRecord balanceResult = TemporalUtil.balanceDuration(getContext(), namesNode, @@ -498,6 +623,7 @@ public JSDynamicObject subtract(Object thisObj, Object temporalDurationLike, Obj } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainDateWith extends JSTemporalBuiltinOperation { protected JSTemporalPlainDateWith(JSContext context, JSBuiltin builtin) { @@ -508,8 +634,9 @@ protected JSTemporalPlainDateWith(JSContext context, JSBuiltin builtin) { public JSDynamicObject with(Object thisObj, Object temporalDateLike, Object optParam, @Cached("createKeys(getContext())") EnumerableOwnPropertyNamesNode nameNode, @Cached("create(getContext())") TemporalCalendarFieldsNode calendarFieldsNode, - @Cached("create(getContext())") TemporalCalendarDateFromFieldsNode dateFromFieldsNode) { - JSTemporalPlainDateObject temporalDate = requireTemporalDate(thisObj); + @Cached("create(getContext())") TemporalCalendarDateFromFieldsNode dateFromFieldsNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalPlainDateObject temporalDate = requireTemporalDate(thisObj, interop, getContext()); if (!isObject(temporalDateLike)) { errorBranch.enter(); throw Errors.createTypeError("Object expected"); @@ -537,6 +664,7 @@ public JSDynamicObject with(Object thisObj, Object temporalDateLike, Object optP } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainDateWithCalendar extends JSTemporalBuiltinOperation { protected JSTemporalPlainDateWithCalendar(JSContext context, JSBuiltin builtin) { @@ -545,13 +673,15 @@ protected JSTemporalPlainDateWithCalendar(JSContext context, JSBuiltin builtin) @Specialization public JSDynamicObject withCalendar(Object thisObj, Object calendarParam, - @Cached("create(getContext())") ToTemporalCalendarNode toTemporalCalendar) { - JSTemporalPlainDateObject td = requireTemporalDate(thisObj); + @Cached("create(getContext())") ToTemporalCalendarNode toTemporalCalendar, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalPlainDateObject td = requireTemporalDate(thisObj, interop, getContext()); JSDynamicObject calendar = toTemporalCalendar.executeDynamicObject(calendarParam); return JSTemporalPlainDate.create(getContext(), td.getYear(), td.getMonth(), td.getDay(), calendar, errorBranch); } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainDateSince extends JSTemporalBuiltinOperation { protected JSTemporalPlainDateSince(JSContext context, JSBuiltin builtin) { @@ -565,9 +695,10 @@ public JSDynamicObject since(Object thisObj, Object otherObj, Object optionsPara @Cached("create(getContext())") ToTemporalDateNode toTemporalDate, @Cached JSToStringNode toStringNode, @Cached TruffleString.EqualNode equalNode, - @Cached("create(getContext())") TemporalRoundDurationNode roundDurationNode) { - JSTemporalPlainDateObject temporalDate = requireTemporalDate(thisObj); - JSTemporalPlainDateObject other = toTemporalDate.executeDynamicObject(otherObj, Undefined.instance); + @Cached("create(getContext())") TemporalRoundDurationNode roundDurationNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalPlainDateObject temporalDate = requireTemporalDate(thisObj, interop, getContext()); + JSTemporalPlainDateObject other = toTemporalDate.executeDynamicObject(convertJavaToJavascriptPlainDate(otherObj, interop, getContext()), Undefined.instance); if (!TemporalUtil.calendarEquals(temporalDate.getCalendar(), other.getCalendar(), toStringNode)) { errorBranch.enter(); throw TemporalErrors.createRangeErrorIdenticalCalendarExpected(); @@ -595,6 +726,7 @@ public JSDynamicObject since(Object thisObj, Object otherObj, Object optionsPara } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainDateUntil extends JSTemporalBuiltinOperation { protected JSTemporalPlainDateUntil(JSContext context, JSBuiltin builtin) { @@ -608,9 +740,10 @@ public JSDynamicObject until(Object thisObj, Object otherObj, Object optionsPara @Cached("create(getContext())") ToTemporalDateNode toTemporalDate, @Cached JSToStringNode toStringNode, @Cached TruffleString.EqualNode equalNode, - @Cached("create(getContext())") TemporalRoundDurationNode roundDurationNode) { - JSTemporalPlainDateObject temporalDate = requireTemporalDate(thisObj); - JSTemporalPlainDateObject other = toTemporalDate.executeDynamicObject(otherObj, Undefined.instance); + @Cached("create(getContext())") TemporalRoundDurationNode roundDurationNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalPlainDateObject temporalDate = requireTemporalDate(thisObj, interop, getContext()); + JSTemporalPlainDateObject other = toTemporalDate.executeDynamicObject(convertJavaToJavascriptPlainDate(otherObj, interop, getContext()), Undefined.instance); if (!TemporalUtil.calendarEquals(temporalDate.getCalendar(), other.getCalendar(), toStringNode)) { errorBranch.enter(); throw TemporalErrors.createRangeErrorIdenticalCalendarExpected(); @@ -635,6 +768,7 @@ public JSDynamicObject until(Object thisObj, Object otherObj, Object optionsPara } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainDateGetISOFields extends JSTemporalBuiltinOperation { protected JSTemporalPlainDateGetISOFields(JSContext context, JSBuiltin builtin) { @@ -642,8 +776,9 @@ protected JSTemporalPlainDateGetISOFields(JSContext context, JSBuiltin builtin) } @Specialization - public JSDynamicObject getISOFields(Object thisObj) { - JSTemporalPlainDateObject dt = requireTemporalDate(thisObj); + public JSDynamicObject getISOFields(Object thisObj, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalPlainDateObject dt = requireTemporalDate(thisObj, interop, getContext()); JSObject obj = JSOrdinary.create(getContext(), getRealm()); TemporalUtil.createDataPropertyOrThrow(getContext(), obj, CALENDAR, dt.getCalendar()); TemporalUtil.createDataPropertyOrThrow(getContext(), obj, TemporalConstants.ISO_DAY, dt.getDay()); @@ -653,6 +788,7 @@ public JSDynamicObject getISOFields(Object thisObj) { } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainDateToString extends JSTemporalBuiltinOperation { protected JSTemporalPlainDateToString(JSContext context, JSBuiltin builtin) { @@ -661,14 +797,16 @@ protected JSTemporalPlainDateToString(JSContext context, JSBuiltin builtin) { @Specialization protected TruffleString toString(Object thisObj, Object optionsParam, - @Cached TruffleString.EqualNode equalNode) { - JSTemporalPlainDateObject date = requireTemporalDate(thisObj); + @Cached TruffleString.EqualNode equalNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalPlainDateObject date = requireTemporalDate(thisObj, interop, getContext()); JSDynamicObject options = getOptionsObject(optionsParam); ShowCalendar showCalendar = TemporalUtil.toShowCalendarOption(options, getOptionNode(), equalNode); return JSTemporalPlainDate.temporalDateToString(date, showCalendar); } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainDateToLocaleString extends JSTemporalBuiltinOperation { protected JSTemporalPlainDateToLocaleString(JSContext context, JSBuiltin builtin) { @@ -676,12 +814,14 @@ protected JSTemporalPlainDateToLocaleString(JSContext context, JSBuiltin builtin } @Specialization - public TruffleString toLocaleString(Object thisObj) { - JSTemporalPlainDateObject date = requireTemporalDate(thisObj); + public TruffleString toLocaleString(Object thisObj, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalPlainDateObject date = requireTemporalDate(thisObj, interop, getContext()); return JSTemporalPlainDate.temporalDateToString(date, ShowCalendar.AUTO); } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainDateValueOf extends JSTemporalBuiltinOperation { protected JSTemporalPlainDateValueOf(JSContext context, JSBuiltin builtin) { @@ -694,6 +834,7 @@ protected Object valueOf(@SuppressWarnings("unused") Object thisObj) { } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainDateToPlainDateTime extends JSTemporalBuiltinOperation { protected JSTemporalPlainDateToPlainDateTime(JSContext context, JSBuiltin builtin) { @@ -702,8 +843,9 @@ protected JSTemporalPlainDateToPlainDateTime(JSContext context, JSBuiltin builti @Specialization public JSDynamicObject toPlainDateTime(Object thisObj, Object temporalTimeObj, - @Cached("create(getContext())") ToTemporalTimeNode toTemporalTime) { - JSTemporalPlainDateObject date = requireTemporalDate(thisObj); + @Cached("create(getContext())") ToTemporalTimeNode toTemporalTime, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalPlainDateObject date = requireTemporalDate(thisObj, interop, getContext()); if (temporalTimeObj == Undefined.instance) { return JSTemporalPlainDateTime.create(getContext(), date.getYear(), date.getMonth(), date.getDay(), 0, 0, 0, 0, 0, 0, date.getCalendar(), errorBranch); } @@ -714,6 +856,7 @@ public JSDynamicObject toPlainDateTime(Object thisObj, Object temporalTimeObj, } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainDateToPlainYearMonth extends JSTemporalBuiltinOperation { protected JSTemporalPlainDateToPlainYearMonth(JSContext context, JSBuiltin builtin) { @@ -723,8 +866,9 @@ protected JSTemporalPlainDateToPlainYearMonth(JSContext context, JSBuiltin built @Specialization public JSDynamicObject toPlainYearMonth(Object thisObj, @Cached("create(getContext())") TemporalYearMonthFromFieldsNode yearMonthFromFieldsNode, - @Cached("create(getContext())") TemporalCalendarFieldsNode calendarFieldsNode) { - JSTemporalPlainDateObject date = requireTemporalDate(thisObj); + @Cached("create(getContext())") TemporalCalendarFieldsNode calendarFieldsNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalPlainDateObject date = requireTemporalDate(thisObj, interop, getContext()); JSDynamicObject calendar = date.getCalendar(); List fieldNames = calendarFieldsNode.execute(calendar, TemporalUtil.listMCY); JSDynamicObject fields = TemporalUtil.prepareTemporalFields(getContext(), date, fieldNames, TemporalUtil.listEmpty); @@ -732,6 +876,7 @@ public JSDynamicObject toPlainYearMonth(Object thisObj, } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainDateToPlainMonthDay extends JSTemporalBuiltinOperation { protected JSTemporalPlainDateToPlainMonthDay(JSContext context, JSBuiltin builtin) { @@ -741,8 +886,9 @@ protected JSTemporalPlainDateToPlainMonthDay(JSContext context, JSBuiltin builti @Specialization public JSDynamicObject toPlainMonthDay(Object thisObj, @Cached("create(getContext())") TemporalMonthDayFromFieldsNode monthDayFromFieldsNode, - @Cached("create(getContext())") TemporalCalendarFieldsNode calendarFieldsNode) { - JSTemporalPlainDateObject date = requireTemporalDate(thisObj); + @Cached("create(getContext())") TemporalCalendarFieldsNode calendarFieldsNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalPlainDateObject date = requireTemporalDate(thisObj, interop, getContext()); JSDynamicObject calendar = date.getCalendar(); List fieldNames = calendarFieldsNode.execute(calendar, TemporalUtil.listDMC); JSDynamicObject fields = TemporalUtil.prepareTemporalFields(getContext(), date, fieldNames, TemporalUtil.listEmpty); @@ -750,6 +896,7 @@ public JSDynamicObject toPlainMonthDay(Object thisObj, } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainDateEquals extends JSTemporalBuiltinOperation { protected JSTemporalPlainDateEquals(JSContext context, JSBuiltin builtin) { @@ -759,9 +906,10 @@ protected JSTemporalPlainDateEquals(JSContext context, JSBuiltin builtin) { @Specialization public boolean equals(Object thisObj, Object otherParam, @Cached("create(getContext())") ToTemporalDateNode toTemporalDate, - @Cached JSToStringNode toStringNode) { - JSTemporalPlainDateObject temporalDate = requireTemporalDate(thisObj); - JSTemporalPlainDateObject other = toTemporalDate.executeDynamicObject(otherParam, Undefined.instance); + @Cached JSToStringNode toStringNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalPlainDateObject temporalDate = requireTemporalDate(thisObj, interop, getContext()); + JSTemporalPlainDateObject other = toTemporalDate.executeDynamicObject(convertJavaToJavascriptPlainDate(otherParam, interop, getContext()), Undefined.instance); if (temporalDate.getYear() != other.getYear()) { return false; } @@ -775,6 +923,7 @@ public boolean equals(Object thisObj, Object otherParam, } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainDateToZonedDateTimeNode extends JSTemporalBuiltinOperation { protected JSTemporalPlainDateToZonedDateTimeNode(JSContext context, JSBuiltin builtin) { @@ -786,8 +935,9 @@ public JSDynamicObject toZonedDateTime(Object thisObj, Object item, @Cached ConditionProfile timeZoneIsUndefined, @Cached ConditionProfile timeIsUndefined, @Cached("create(getContext())") ToTemporalTimeNode toTemporalTime, - @Cached("create(getContext())") ToTemporalTimeZoneNode toTemporalTimeZone) { - JSTemporalPlainDateObject td = requireTemporalDate(thisObj); + @Cached("create(getContext())") ToTemporalTimeZoneNode toTemporalTimeZone, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalPlainDateObject td = requireTemporalDate(thisObj, interop, getContext()); JSTemporalTimeZoneObject timeZone; Object temporalTime; JSTemporalPlainDateTimeObject temporalDateTime; 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 34ee1a49df4..90fa822db7a 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 @@ -56,7 +56,12 @@ 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.interop.InteropLibrary; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.library.CachedLibrary; +import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.builtins.JSBuiltinsContainer; import com.oracle.truffle.js.builtins.temporal.TemporalPlainDatePrototypeBuiltins.JSTemporalBuiltinOperation; @@ -87,6 +92,7 @@ import com.oracle.truffle.js.nodes.temporal.ToTemporalTimeNode; import com.oracle.truffle.js.nodes.temporal.ToTemporalTimeZoneNode; import com.oracle.truffle.js.runtime.Errors; +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.Strings; @@ -95,6 +101,7 @@ 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.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; @@ -207,6 +214,7 @@ protected Object createNode(JSContext context, JSBuiltin builtin, boolean constr return null; } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainTimeGetterNode extends JSBuiltinNode { public final TemporalPlainTimePrototype property; @@ -216,6 +224,7 @@ public JSTemporalPlainTimeGetterNode(JSContext context, JSBuiltin builtin, Tempo this.property = property; } + @CompilerDirectives.TruffleBoundary @Specialization(guards = "isJSTemporalTime(thisObj)") protected Object timeGetter(Object thisObj) { TemporalTime temporalTime = (TemporalTime) thisObj; @@ -243,9 +252,27 @@ protected Object timeGetter(Object thisObj) { protected static int error(@SuppressWarnings("unused") Object thisObj) { throw TemporalErrors.createTypeErrorTemporalDateTimeExpected(); } + + @CompilerDirectives.TruffleBoundary + public static JSTemporalPlainTimeObject javaPlainTimeToPlainTime(Object thisObj, InteropLibrary interop, JSContext context, BranchProfile errorBranch) { + try { + java.time.LocalTime time = interop.asTime(thisObj); + int hours = time.getHour(); + int minutes = time.getMinute(); + int seconds = time.getSecond(); + int milliseconds = (int) Math.floor(time.getNano() / 1_000_000) % 1_000; + int microseconds = (int) Math.floor(time.getNano() / 1_000) % 1_000; + int nanoseconds = time.getNano() % 1_000; + + return JSTemporalPlainTime.create(context, hours, minutes, seconds, milliseconds, microseconds, nanoseconds, errorBranch); + } catch (UnsupportedMessageException e) { + return null; + } + } } // 4.3.10 + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainTimeAdd extends JSTemporalBuiltinOperation { protected JSTemporalPlainTimeAdd(JSContext context, JSBuiltin builtin) { @@ -254,8 +281,9 @@ protected JSTemporalPlainTimeAdd(JSContext context, JSBuiltin builtin) { @Specialization public JSDynamicObject add(Object thisObj, Object temporalDurationLike, - @Cached("create()") ToLimitedTemporalDurationNode toLimitedTemporalDurationNode) { - TemporalTime temporalTime = requireTemporalTime(thisObj); + @Cached("create()") ToLimitedTemporalDurationNode toLimitedTemporalDurationNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + TemporalTime temporalTime = requireTemporalTime(thisObj, interop, getContext()); JSTemporalDurationRecord duration = toLimitedTemporalDurationNode.executeDynamicObject(temporalDurationLike, TemporalUtil.listEmpty); TemporalUtil.rejectDurationSign( duration.getYears(), duration.getMonths(), duration.getWeeks(), duration.getDays(), @@ -277,6 +305,7 @@ public JSDynamicObject add(Object thisObj, Object temporalDurationLike, } // 4.3.11 + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainTimeSubtract extends JSTemporalBuiltinOperation { protected JSTemporalPlainTimeSubtract(JSContext context, JSBuiltin builtin) { @@ -285,8 +314,9 @@ protected JSTemporalPlainTimeSubtract(JSContext context, JSBuiltin builtin) { @Specialization public JSDynamicObject subtract(Object thisObj, Object temporalDurationLike, - @Cached("create()") ToLimitedTemporalDurationNode toLimitedTemporalDurationNode) { - TemporalTime temporalTime = requireTemporalTime(thisObj); + @Cached("create()") ToLimitedTemporalDurationNode toLimitedTemporalDurationNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + TemporalTime temporalTime = requireTemporalTime(thisObj, interop, getContext()); JSTemporalDurationRecord duration = toLimitedTemporalDurationNode.executeDynamicObject(temporalDurationLike, TemporalUtil.listEmpty); TemporalUtil.rejectDurationSign( duration.getYears(), duration.getMonths(), duration.getWeeks(), duration.getDays(), @@ -307,6 +337,7 @@ public JSDynamicObject subtract(Object thisObj, Object temporalDurationLike, } // 4.3.12 + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainTimeWith extends JSTemporalBuiltinOperation { protected JSTemporalPlainTimeWith(JSContext context, JSBuiltin builtin) { @@ -316,8 +347,9 @@ protected JSTemporalPlainTimeWith(JSContext context, JSBuiltin builtin) { @Specialization protected JSDynamicObject with(Object thisObj, Object temporalTimeLike, Object options, @Cached("create()") JSToIntegerThrowOnInfinityNode toIntThrows, - @Cached("create()") JSToIntegerAsIntNode toInt) { - TemporalTime temporalTime = requireTemporalTime(thisObj); + @Cached("create()") JSToIntegerAsIntNode toInt, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + TemporalTime temporalTime = requireTemporalTime(thisObj, interop, getContext()); if (!isObject(temporalTimeLike)) { errorBranch.enter(); throw Errors.createTypeError("Temporal.Time like object expected."); @@ -387,6 +419,7 @@ protected JSDynamicObject with(Object thisObj, Object temporalTimeLike, Object o } // 4.3.13 + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainTimeUntil extends JSTemporalBuiltinOperation { protected JSTemporalPlainTimeUntil(JSContext context, JSBuiltin builtin) { @@ -398,9 +431,11 @@ public JSDynamicObject until(Object thisObj, Object otherObj, Object optionsPara @Cached("create()") JSToNumberNode toNumber, @Cached("createKeys(getContext())") EnumerableOwnPropertyNamesNode namesNode, @Cached("create(getContext())") ToTemporalTimeNode toTemporalTime, - @Cached TruffleString.EqualNode equalNode, @Cached("create(getContext())") TemporalRoundDurationNode roundDurationNode) { - TemporalTime temporalTime = requireTemporalTime(thisObj); - JSTemporalPlainTimeObject other = (JSTemporalPlainTimeObject) toTemporalTime.executeDynamicObject(otherObj, null); + @Cached TruffleString.EqualNode equalNode, + @Cached("create(getContext())") TemporalRoundDurationNode roundDurationNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + TemporalTime temporalTime = requireTemporalTime(thisObj, interop, getContext()); + JSTemporalPlainTimeObject other = (JSTemporalPlainTimeObject) toTemporalTime.executeDynamicObject(convertJavaToJavascriptPlainTime(otherObj, interop, getContext()), null); JSDynamicObject options = getOptionsObject(optionsParam); Unit smallestUnit = toSmallestTemporalUnit(options, TemporalUtil.listYMWD, NANOSECOND, equalNode); Unit largestUnit = toLargestTemporalUnit(options, TemporalUtil.listYMWD, AUTO, Unit.HOUR, equalNode); @@ -424,6 +459,7 @@ public JSDynamicObject until(Object thisObj, Object otherObj, Object optionsPara } // 4.3.14 + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainTimeSince extends JSTemporalBuiltinOperation { protected JSTemporalPlainTimeSince(JSContext context, JSBuiltin builtin) { @@ -436,9 +472,10 @@ public JSDynamicObject since(Object thisObj, Object otherObj, Object optionsPara @Cached("createKeys(getContext())") EnumerableOwnPropertyNamesNode namesNode, @Cached("create(getContext())") ToTemporalTimeNode toTemporalTime, @Cached TruffleString.EqualNode equalNode, - @Cached("create(getContext())") TemporalRoundDurationNode roundDurationNode) { - TemporalTime temporalTime = requireTemporalTime(thisObj); - JSTemporalPlainTimeObject other = (JSTemporalPlainTimeObject) toTemporalTime.executeDynamicObject(otherObj, null); + @Cached("create(getContext())") TemporalRoundDurationNode roundDurationNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + TemporalTime temporalTime = requireTemporalTime(thisObj, interop, getContext()); + JSTemporalPlainTimeObject other = (JSTemporalPlainTimeObject) toTemporalTime.executeDynamicObject(convertJavaToJavascriptPlainTime(otherObj, interop, getContext()), null); JSDynamicObject options = getOptionsObject(optionsParam); Unit smallestUnit = toSmallestTemporalUnit(options, TemporalUtil.listYMWD, NANOSECOND, equalNode); Unit largestUnit = toLargestTemporalUnit(options, TemporalUtil.listYMWD, AUTO, Unit.HOUR, equalNode); @@ -464,6 +501,7 @@ public JSDynamicObject since(Object thisObj, Object otherObj, Object optionsPara } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainTimeRound extends JSTemporalBuiltinOperation { protected JSTemporalPlainTimeRound(JSContext context, JSBuiltin builtin) { @@ -473,8 +511,9 @@ protected JSTemporalPlainTimeRound(JSContext context, JSBuiltin builtin) { @Specialization protected JSDynamicObject round(Object thisObj, Object roundToParam, @Cached("create()") JSToNumberNode toNumber, - @Cached TruffleString.EqualNode equalNode) { - TemporalTime temporalTime = requireTemporalTime(thisObj); + @Cached TruffleString.EqualNode equalNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + TemporalTime temporalTime = requireTemporalTime(thisObj, interop, getContext()); if (roundToParam == Undefined.instance) { errorBranch.enter(); throw TemporalErrors.createTypeErrorOptionsUndefined(); @@ -512,6 +551,7 @@ protected JSDynamicObject round(Object thisObj, Object roundToParam, } // 4.3.16 + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainTimeEquals extends JSTemporalBuiltinOperation { protected JSTemporalPlainTimeEquals(JSContext context, JSBuiltin builtin) { @@ -519,16 +559,18 @@ protected JSTemporalPlainTimeEquals(JSContext context, JSBuiltin builtin) { } @Specialization(guards = "isJSTemporalTime(otherObj)") - protected boolean equalsOtherObj(Object thisObj, JSDynamicObject otherObj) { - TemporalTime temporalTime = requireTemporalTime(thisObj); + protected boolean equalsOtherObj(Object thisObj, JSDynamicObject otherObj, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + TemporalTime temporalTime = requireTemporalTime(thisObj, interop, getContext()); return equalsIntl(temporalTime, (TemporalTime) otherObj); } @Specialization(guards = "!isJSTemporalTime(other)") protected boolean equalsGeneric(Object thisObj, Object other, - @Cached("create(getContext())") ToTemporalTimeNode toTemporalTime) { - TemporalTime temporalTime = requireTemporalTime(thisObj); - TemporalTime otherTime = (TemporalTime) toTemporalTime.executeDynamicObject(other, null); + @Cached("create(getContext())") ToTemporalTimeNode toTemporalTime, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + TemporalTime temporalTime = requireTemporalTime(thisObj, interop, getContext()); + TemporalTime otherTime = (TemporalTime) toTemporalTime.executeDynamicObject(convertJavaToJavascriptPlainTime(other, interop, getContext()), null); return equalsIntl(temporalTime, otherTime); } @@ -556,6 +598,7 @@ private static boolean equalsIntl(TemporalTime thisTime, TemporalTime otherTime) } // 4.3.17 + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainTimeToPlainDateTime extends JSTemporalBuiltinOperation { protected JSTemporalPlainTimeToPlainDateTime(JSContext context, JSBuiltin builtin) { @@ -564,8 +607,9 @@ protected JSTemporalPlainTimeToPlainDateTime(JSContext context, JSBuiltin builti @Specialization public JSDynamicObject toPlainDateTime(Object thisObj, Object temporalDateObj, - @Cached("create(getContext())") ToTemporalDateNode toTemporalDate) { - TemporalTime time = requireTemporalTime(thisObj); + @Cached("create(getContext())") ToTemporalDateNode toTemporalDate, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + TemporalTime time = requireTemporalTime(thisObj, interop, getContext()); JSDynamicObject temporalDate = toTemporalDate.executeDynamicObject(temporalDateObj, Undefined.instance); JSTemporalPlainDateObject date = (JSTemporalPlainDateObject) temporalDate; @@ -576,6 +620,7 @@ public JSDynamicObject toPlainDateTime(Object thisObj, Object temporalDateObj, } // 4.3.18 + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainTimeToZonedDateTime extends JSTemporalBuiltinOperation { protected JSTemporalPlainTimeToZonedDateTime(JSContext context, JSBuiltin builtin) { @@ -585,8 +630,9 @@ protected JSTemporalPlainTimeToZonedDateTime(JSContext context, JSBuiltin builti @Specialization public JSDynamicObject toZonedDateTime(Object thisObj, Object itemParam, @Cached("create(getContext())") ToTemporalDateNode toTemporalDate, - @Cached("create(getContext())") ToTemporalTimeZoneNode toTemporalTimeZone) { - TemporalTime time = requireTemporalTime(thisObj); + @Cached("create(getContext())") ToTemporalTimeZoneNode toTemporalTimeZone, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + TemporalTime time = requireTemporalTime(thisObj, interop, getContext()); if (!JSRuntime.isObject(itemParam)) { throw Errors.createTypeErrorNotAnObject(itemParam); } @@ -614,6 +660,7 @@ public JSDynamicObject toZonedDateTime(Object thisObj, Object itemParam, } // 4.3.19 + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainTimeGetISOFields extends JSTemporalBuiltinOperation { protected JSTemporalPlainTimeGetISOFields(JSContext context, JSBuiltin builtin) { @@ -621,8 +668,9 @@ protected JSTemporalPlainTimeGetISOFields(JSContext context, JSBuiltin builtin) } @Specialization - protected Object getISOFields(Object thisObj) { - TemporalTime time = requireTemporalTime(thisObj); + protected Object getISOFields(Object thisObj, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + TemporalTime time = requireTemporalTime(thisObj, interop, getContext()); JSObject fields = JSOrdinary.create(getContext(), getRealm()); TemporalUtil.createDataPropertyOrThrow(getContext(), fields, TemporalConstants.CALENDAR, time.getCalendar()); TemporalUtil.createDataPropertyOrThrow(getContext(), fields, TemporalConstants.ISO_HOUR, time.getHour()); @@ -636,6 +684,7 @@ protected Object getISOFields(Object thisObj) { } // 4.3.20 + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainTimeToString extends JSTemporalBuiltinOperation { protected JSTemporalPlainTimeToString(JSContext context, JSBuiltin builtin) { @@ -645,8 +694,9 @@ protected JSTemporalPlainTimeToString(JSContext context, JSBuiltin builtin) { @Specialization protected TruffleString toString(Object thisObj, Object optionsParam, @Cached JSToStringNode toStringNode, - @Cached TruffleString.EqualNode equalNode) { - TemporalTime time = requireTemporalTime(thisObj); + @Cached TruffleString.EqualNode equalNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + TemporalTime time = requireTemporalTime(thisObj, interop, getContext()); JSDynamicObject options = getOptionsObject(optionsParam); JSTemporalPrecisionRecord precision = TemporalUtil.toSecondsStringPrecision(options, toStringNode, getOptionNode(), equalNode); RoundingMode roundingMode = toTemporalRoundingMode(options, TemporalConstants.TRUNC, equalNode); @@ -663,6 +713,7 @@ protected TruffleString toString(Object thisObj, Object optionsParam, // 4.3.21 // 4.3.22 + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainTimeToLocaleString extends JSTemporalBuiltinOperation { protected JSTemporalPlainTimeToLocaleString(JSContext context, JSBuiltin builtin) { @@ -670,8 +721,9 @@ protected JSTemporalPlainTimeToLocaleString(JSContext context, JSBuiltin builtin } @Specialization - public TruffleString toLocaleString(Object thisObj) { - TemporalTime time = requireTemporalTime(thisObj); + public TruffleString toLocaleString(Object thisObj, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + TemporalTime time = requireTemporalTime(thisObj, interop, getContext()); return JSTemporalPlainTime.temporalTimeToString( time.getHour(), time.getMinute(), time.getSecond(), time.getMillisecond(), time.getMicrosecond(), time.getNanosecond(), @@ -680,6 +732,7 @@ public TruffleString toLocaleString(Object thisObj) { } // 4.3.23 + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalPlainTimeValueOf extends JSTemporalBuiltinOperation { protected JSTemporalPlainTimeValueOf(JSContext context, JSBuiltin builtin) { 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 447fdfdb445..68563dcd44f 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 @@ -49,7 +49,11 @@ import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; 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.interop.UnsupportedMessageException; +import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.strings.TruffleString; import com.oracle.truffle.js.builtins.JSBuiltinsContainer; import com.oracle.truffle.js.builtins.temporal.TemporalPlainDatePrototypeBuiltins.JSTemporalBuiltinOperation; @@ -71,6 +75,7 @@ import com.oracle.truffle.js.nodes.temporal.ToTemporalInstantNode; import com.oracle.truffle.js.runtime.BigInt; import com.oracle.truffle.js.runtime.Errors; +import com.oracle.truffle.js.runtime.JSConfig; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.JSRealm; import com.oracle.truffle.js.runtime.JSRuntime; @@ -78,6 +83,7 @@ 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.JSTemporalPlainDateTimeObject; +import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalPlainTime; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalTimeZone; import com.oracle.truffle.js.runtime.builtins.temporal.JSTemporalTimeZoneObject; import com.oracle.truffle.js.runtime.objects.JSDynamicObject; @@ -158,6 +164,7 @@ protected Object createNode(JSContext context, JSBuiltin builtin, boolean constr return null; } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalTimeZoneGetterNode extends JSBuiltinNode { public final TemporalTimeZonePrototype property; @@ -167,6 +174,7 @@ public JSTemporalTimeZoneGetterNode(JSContext context, JSBuiltin builtin, Tempor this.property = property; } + @CompilerDirectives.TruffleBoundary @Specialization(guards = "isJSTemporalTimeZone(thisObj)") protected TruffleString timeZoneGetter(Object thisObj, @Cached JSToStringNode toStringNode) { @@ -183,8 +191,21 @@ protected TruffleString timeZoneGetter(Object thisObj, protected static int error(@SuppressWarnings("unused") Object thisObj) { throw TemporalErrors.createTypeErrorTemporalTimeZoneExpected(); } + + @CompilerDirectives.TruffleBoundary + public static JSTemporalTimeZoneObject javaTimeZoneToTimeZone(Object thisObj, InteropLibrary interop, JSContext ctx) { + try { + java.time.ZoneId zone = interop.asTimeZone(thisObj); + TruffleString identifier = TruffleString.fromJavaStringUncached(zone.getId(), TruffleString.Encoding.UTF_32); + + return JSTemporalTimeZone.create(ctx, null, identifier); + } catch (UnsupportedMessageException e) { + return null; + } + } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalTimeZoneToString extends JSTemporalBuiltinOperation { protected JSTemporalTimeZoneToString(JSContext context, JSBuiltin builtin) { @@ -192,11 +213,13 @@ protected JSTemporalTimeZoneToString(JSContext context, JSBuiltin builtin) { } @Specialization - protected TruffleString toString(Object thisObj) { - return requireTemporalTimeZone(thisObj).getIdentifier(); + protected TruffleString toString(Object thisObj, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + return requireTemporalTimeZone(thisObj, interop, getContext()).getIdentifier(); } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalTimeZoneToJSON extends JSTemporalBuiltinOperation { protected JSTemporalTimeZoneToJSON(JSContext context, JSBuiltin builtin) { @@ -205,12 +228,14 @@ protected JSTemporalTimeZoneToJSON(JSContext context, JSBuiltin builtin) { @Specialization protected TruffleString toJSON(Object thisObj, - @Cached("create()") JSToStringNode toString) { - JSTemporalTimeZoneObject timeZone = requireTemporalTimeZone(thisObj); + @Cached("create()") JSToStringNode toString, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalTimeZoneObject timeZone = requireTemporalTimeZone(thisObj, interop, getContext()); return toString.executeString(timeZone); } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalTimeZoneValueOf extends JSTemporalBuiltinOperation { protected JSTemporalTimeZoneValueOf(JSContext context, JSBuiltin builtin) { @@ -223,6 +248,7 @@ protected Object valueOf(@SuppressWarnings("unused") Object thisObj) { } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalTimeZoneGetOffsetNanosecondsFor extends JSTemporalBuiltinOperation { protected JSTemporalTimeZoneGetOffsetNanosecondsFor(JSContext context, JSBuiltin builtin) { @@ -231,8 +257,9 @@ protected JSTemporalTimeZoneGetOffsetNanosecondsFor(JSContext context, JSBuiltin @Specialization protected double getOffsetNanosecondsFor(Object thisObj, Object instantParam, - @Cached("create(getContext())") ToTemporalInstantNode toTemporalInstantNode) { - JSTemporalTimeZoneObject timeZone = requireTemporalTimeZone(thisObj); + @Cached("create(getContext())") ToTemporalInstantNode toTemporalInstantNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalTimeZoneObject timeZone = requireTemporalTimeZone(thisObj, interop, getContext()); JSTemporalInstantObject instant = toTemporalInstantNode.execute(instantParam); if (timeZone.getNanoseconds() != null) { return timeZone.getNanoseconds().doubleValue(); @@ -241,6 +268,7 @@ protected double getOffsetNanosecondsFor(Object thisObj, Object instantParam, } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalTimeZoneGetOffsetStringFor extends JSTemporalBuiltinOperation { protected JSTemporalTimeZoneGetOffsetStringFor(JSContext context, JSBuiltin builtin) { @@ -249,13 +277,15 @@ protected JSTemporalTimeZoneGetOffsetStringFor(JSContext context, JSBuiltin buil @Specialization protected TruffleString getOffsetStringFor(Object thisObj, Object instantParam, - @Cached("create(getContext())") ToTemporalInstantNode toTemporalInstantNode) { - JSTemporalTimeZoneObject timeZone = requireTemporalTimeZone(thisObj); + @Cached("create(getContext())") ToTemporalInstantNode toTemporalInstantNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalTimeZoneObject timeZone = requireTemporalTimeZone(thisObj, interop, getContext()); JSDynamicObject instant = toTemporalInstantNode.execute(instantParam); return TemporalUtil.builtinTimeZoneGetOffsetStringFor(timeZone, instant); } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalTimeZoneGetPlainDateTimeFor extends JSTemporalBuiltinOperation { protected JSTemporalTimeZoneGetPlainDateTimeFor(JSContext context, JSBuiltin builtin) { @@ -265,14 +295,16 @@ protected JSTemporalTimeZoneGetPlainDateTimeFor(JSContext context, JSBuiltin bui @Specialization protected JSDynamicObject getPlainDateTimeFor(Object thisObj, Object instantParam, Object calendarLike, @Cached("create(getContext())") ToTemporalCalendarWithISODefaultNode toTemporalCalendarWithISODefaultNode, - @Cached("create(getContext())") ToTemporalInstantNode toTemporalInstantNode) { - JSTemporalTimeZoneObject timeZone = requireTemporalTimeZone(thisObj); + @Cached("create(getContext())") ToTemporalInstantNode toTemporalInstantNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalTimeZoneObject timeZone = requireTemporalTimeZone(thisObj, interop, getContext()); JSDynamicObject instant = toTemporalInstantNode.execute(instantParam); JSDynamicObject calendar = toTemporalCalendarWithISODefaultNode.executeDynamicObject(calendarLike); return TemporalUtil.builtinTimeZoneGetPlainDateTimeFor(getContext(), timeZone, instant, calendar); } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalTimeZoneGetInstantFor extends JSTemporalBuiltinOperation { protected JSTemporalTimeZoneGetInstantFor(JSContext context, JSBuiltin builtin) { @@ -282,8 +314,9 @@ protected JSTemporalTimeZoneGetInstantFor(JSContext context, JSBuiltin builtin) @Specialization protected JSDynamicObject getInstantFor(Object thisObj, Object dateTimeParam, Object optionsParam, @Cached("create(getContext())") ToTemporalDateTimeNode toTemporalDateTime, - @Cached TruffleString.EqualNode equalNode) { - JSTemporalTimeZoneObject timeZone = requireTemporalTimeZone(thisObj); + @Cached TruffleString.EqualNode equalNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalTimeZoneObject timeZone = requireTemporalTimeZone(thisObj, interop, getContext()); JSTemporalPlainDateTimeObject dateTime = (JSTemporalPlainDateTimeObject) toTemporalDateTime.executeDynamicObject(dateTimeParam, Undefined.instance); JSDynamicObject options = getOptionsObject(optionsParam); Disambiguation disambiguation = TemporalUtil.toTemporalDisambiguation(options, getOptionNode(), equalNode); @@ -291,6 +324,7 @@ protected JSDynamicObject getInstantFor(Object thisObj, Object dateTimeParam, Ob } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalTimeZoneGetPossibleInstantsFor extends JSTemporalBuiltinOperation { protected JSTemporalTimeZoneGetPossibleInstantsFor(JSContext context, JSBuiltin builtin) { @@ -300,8 +334,9 @@ protected JSTemporalTimeZoneGetPossibleInstantsFor(JSContext context, JSBuiltin @TruffleBoundary @Specialization protected JSDynamicObject getPossibleInstantsFor(Object thisObj, Object dateTimeParam, - @Cached("create(getContext())") ToTemporalDateTimeNode toTemporalDateTime) { - JSTemporalTimeZoneObject timeZone = requireTemporalTimeZone(thisObj); + @Cached("create(getContext())") ToTemporalDateTimeNode toTemporalDateTime, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalTimeZoneObject timeZone = requireTemporalTimeZone(thisObj, interop, getContext()); JSTemporalPlainDateTimeObject dateTime = (JSTemporalPlainDateTimeObject) toTemporalDateTime.executeDynamicObject(dateTimeParam, Undefined.instance); JSRealm realm = getRealm(); if (timeZone.getNanoseconds() != null) { @@ -323,6 +358,7 @@ protected JSDynamicObject getPossibleInstantsFor(Object thisObj, Object dateTime } } + @ImportStatic({JSConfig.class}) public abstract static class JSTemporalTimeZoneGetNextOrPreviousTransition extends JSTemporalBuiltinOperation { private final boolean isNext; @@ -334,8 +370,9 @@ protected JSTemporalTimeZoneGetNextOrPreviousTransition(JSContext context, JSBui @Specialization protected JSDynamicObject getTransition(Object thisObj, Object startingPointParam, - @Cached("create(getContext())") ToTemporalInstantNode toTemporalInstantNode) { - JSTemporalTimeZoneObject timeZone = requireTemporalTimeZone(thisObj); + @Cached("create(getContext())") ToTemporalInstantNode toTemporalInstantNode, + @CachedLibrary(limit = "InteropLibraryLimit") InteropLibrary interop) { + JSTemporalTimeZoneObject timeZone = requireTemporalTimeZone(thisObj, interop, getContext()); JSTemporalInstantObject startingPoint = toTemporalInstantNode.execute(startingPointParam); if (timeZone.getNanoseconds() != null) { return Null.instance; diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/interop/ForeignObjectPrototypeNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/interop/ForeignObjectPrototypeNode.java index 995108ea5d7..189b15eef7c 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/interop/ForeignObjectPrototypeNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/interop/ForeignObjectPrototypeNode.java @@ -61,14 +61,22 @@ public abstract class ForeignObjectPrototypeNode extends JavaScriptBaseNode { @Specialization(limit = "InteropLibraryLimit") public JSDynamicObject doTruffleObject(Object truffleObject, - @CachedLibrary("truffleObject") InteropLibrary interop) { + @CachedLibrary("truffleObject") InteropLibrary interop) { JSRealm realm = getRealm(); if (interop.hasArrayElements(truffleObject)) { return realm.getArrayPrototype(); + } else if (interop.isInstant(truffleObject)) { + return realm.getTemporalInstantPrototype(); + } else if (interop.isDuration(truffleObject)) { + return realm.getTemporalDurationPrototype(); + } else if (interop.isDate(truffleObject)) { + return realm.getTemporalPlainDatePrototype(); + } else if (interop.isTime(truffleObject)) { + return realm.getTemporalPlainTimePrototype(); + } else if (interop.isTimeZone(truffleObject)) { + return realm.getTemporalTimeZonePrototype(); } else if (interop.isExecutable(truffleObject) || interop.isInstantiable(truffleObject)) { return realm.getFunctionPrototype(); - } else if (interop.isInstant(truffleObject)) { - return realm.getDatePrototype(); } else if (interop.hasHashEntries(truffleObject)) { return realm.getMapPrototype(); } else if (interop.hasIterator(truffleObject)) { @@ -91,4 +99,4 @@ public static ForeignObjectPrototypeNode create() { public static ForeignObjectPrototypeNode getUncached() { return ForeignObjectPrototypeNodeGen.getUncached(); } -} +} \ No newline at end of file