Skip to content

Commit f202969

Browse files
committed
[GR-44198] Adopt BigInteger Interop Support.
PullRequest: js/2725
2 parents 7ee469a + b8f1bf4 commit f202969

File tree

93 files changed

+2716
-1158
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

93 files changed

+2716
-1158
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ See [version roadmap](https://www.graalvm.org/release-notes/version-roadmap/) fo
1515
* Implemented the [Symbols as WeakMap keys](https://github.com/tc39/proposal-symbols-as-weakmap-keys) proposal. It is available in ECMAScript staging mode (`--js.ecmascript-version=staging`).
1616
* Implemented the [ArrayBuffer.prototype.transfer and friends](https://github.com/tc39/proposal-arraybuffer-transfer) proposal. It is available in ECMAScript staging mode (`--js.ecmascript-version=staging`).
1717
* Implemented the [Change Array by copy](https://github.com/tc39/proposal-change-array-by-copy) proposal. It is available in ECMAScript staging mode (`--js.ecmascript-version=staging`).
18+
* Added BigInteger interop support.
19+
Note that foreign BigIntegers require an explicit type cast using the `BigInt` function to opt into JS BigInt semantics.
20+
The default semantics is to treat all foreign numbers like JS Number values, regardless of the original value or type.
21+
Arithmetic operators perform an implicit lossy conversion to double; mixing a JS BigInt with any non-JS number always throws.
22+
Comparison operators attempt to do a precise value comparison where possible.
23+
JS BigInt values can now be converted to `java.math.BigInteger` host objects, although a [target type mapping](https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/HostAccess.Builder.html#targetTypeMapping-java.lang.Class-java.lang.Class-java.util.function.Predicate-java.util.function.Function-) may still be necessary to ensure consistent type mapping if the target type is ambiguous or absent.
1824

1925
## Version 22.3.0
2026
* Implemented the [WebAssembly multi-value](https://github.com/WebAssembly/multi-value) proposal.

graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSTranslator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3668,7 +3668,7 @@ public JavaScriptNode enterWithNode(com.oracle.js.parser.ir.WithNode withNode) {
36683668
Environment withParentEnv = (function.hasClosures() || function.hasEval()) ? new BlockEnvironment(environment, factory, context) : environment;
36693669
try (EnvironmentCloseable withParent = new EnvironmentCloseable(withParentEnv)) {
36703670
JavaScriptNode withExpression = transform(withNode.getExpression());
3671-
JavaScriptNode toObject = factory.createToObjectFromWith(context, withExpression, true);
3671+
JavaScriptNode toObject = factory.createToObjectForWithStatement(context, withExpression);
36723672
InternalSlotId withVarName = makeUniqueTempVarNameForStatement(Strings.WITH, withNode.getLineNumber());
36733673
environment.declareInternalSlot(withVarName);
36743674
JavaScriptNode writeWith = environment.findInternalSlot(withVarName).createWriteNode(toObject);

graal-js/src/com.oracle.truffle.js.snapshot/src/com/oracle/truffle/js/snapshot/Recording.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -1110,9 +1110,10 @@ private static class VarIdTable {
11101110
private final Map<Object, Integer> varIndexMap = new HashMap<>();
11111111

11121112
private static Object getKey(Object node) {
1113-
if (node == null || JSRuntime.isJSPrimitive(node) || node.getClass().isEnum()) {
1113+
if (node == null || JSRuntime.isJSPrimitive(node) || node instanceof Long || node.getClass().isEnum()) {
11141114
return node;
11151115
} else {
1116+
assert !JSRuntime.isJavaPrimitive(node) : node;
11161117
class IdentityKey {
11171118
private final Object obj;
11181119

@@ -1295,7 +1296,7 @@ private Inst dumpSourceSection(SourceSection arg) {
12951296

12961297
private Inst encode(Object arg, Class<?> declaredType, Type genericType) {
12971298
Inst enc;
1298-
if (arg == null || JSRuntime.isJSPrimitive(arg) || arg == Dead.instance()) {
1299+
if (arg == null || JSRuntime.isJSPrimitive(arg) || arg instanceof Long || arg == Dead.instance()) {
12991300
enc = dumpConst(arg, unboxedType(arg, declaredType));
13001301
} else if (arg.getClass().isEnum()) {
13011302
enc = dumpConst(arg, declaredType);

graal-js/src/com.oracle.truffle.js.test.sdk/src/com/oracle/truffle/js/test/sdk/tck/JavaScriptTCKLanguageProvider.java

Lines changed: 190 additions & 46 deletions
Large diffs are not rendered by default.
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright (c) 2023, 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl.
6+
*/
7+
8+
/*
9+
* Test java.math.BigInteger interop.
10+
*/
11+
12+
load('../assert.js');
13+
14+
const BigInteger = java.math.BigInteger;
15+
16+
let zero = BigInteger.ZERO;
17+
let small= BigInteger.valueOf(42);
18+
let long = new BigInteger("9223372036854775807"); // Long.MAX_VALUE
19+
let big = new BigInteger("100000000000000000000"); // 10n ** 20n
20+
let huge = BigInteger.valueOf(2).pow(1000);
21+
let bigIntegers = [zero, small, long, big, huge];
22+
23+
function nonStrictThis() {
24+
return this;
25+
}
26+
27+
function int64(b) {
28+
return b.longValue();
29+
}
30+
31+
function uint64(b) {
32+
return b.mod(BigInteger.ONE.shiftLeft(64));
33+
}
34+
35+
for (let b of bigIntegers) {
36+
// typeof value is 'number' for java.math.BigInteger
37+
assertSame('number', typeof b);
38+
assertTrue(typeof b == 'number');
39+
assertSame('number', typeof Object(b));
40+
assertTrue(typeof Object(b) == 'number');
41+
assertSame('number', typeof nonStrictThis.call(b));
42+
assertTrue(typeof nonStrictThis.call(b) == 'number');
43+
44+
assertTrue(b == b.multiply(BigInteger.ONE));
45+
// ToObject should keep foreign members
46+
assertTrue(b == Object(b).multiply(BigInteger.ONE));
47+
assertTrue(b == nonStrictThis.call(b).multiply(BigInteger.ONE));
48+
49+
assertTrue(b == Object(b));
50+
assertTrue(Object(b) == b);
51+
assertTrue(b == BigInt(b));
52+
assertTrue(BigInt(b) == b);
53+
54+
// ToObject does not wrap BigInteger.
55+
assertTrue(b === Object(b));
56+
57+
// Number (double) coercion
58+
assertSame(Number(b), Number.prototype.valueOf.call(b));
59+
assertSame(String(+b), Number.prototype.toString.call(b));
60+
61+
// Avoid double coercion in ToString.
62+
assertSame(b.toString(), String(b));
63+
64+
// ToBigInt does not accept Number, require explicit conversion for now.
65+
let i64a = new BigInt64Array(1);
66+
let u64a = new BigUint64Array(1);
67+
let cast = BigInt(b);
68+
i64a[0] = cast;
69+
u64a[0] = cast;
70+
assertSame(i64a[0], BigInt.asIntN(64, cast));
71+
assertSame(u64a[0], BigInt.asUintN(64, cast));
72+
assertTrue(i64a[0] == int64(b));
73+
assertTrue(u64a[0] == uint64(b));
74+
}

graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/JSTest.java

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -40,16 +40,30 @@
4040
*/
4141
package com.oracle.truffle.js.test;
4242

43-
import com.oracle.truffle.js.runtime.Strings;
43+
import static org.hamcrest.CoreMatchers.startsWith;
44+
import static org.junit.Assert.assertThat;
45+
import static org.junit.Assert.assertTrue;
46+
import static org.junit.Assert.fail;
47+
48+
import java.util.function.Consumer;
49+
4450
import org.graalvm.polyglot.Context;
4551
import org.graalvm.polyglot.Engine;
52+
import org.graalvm.polyglot.PolyglotException;
4653
import org.junit.After;
4754
import org.junit.Assert;
4855
import org.junit.Before;
4956

5057
import com.oracle.truffle.js.lang.JavaScriptLanguage;
58+
import com.oracle.truffle.js.runtime.JSErrorType;
59+
import com.oracle.truffle.js.runtime.Strings;
5160

5261
public abstract class JSTest {
62+
63+
static {
64+
System.setProperty("polyglot.engine.WarnInterpreterOnly", "false");
65+
}
66+
5367
protected TestHelper testHelper;
5468

5569
@Before
@@ -73,4 +87,23 @@ public static Engine.Builder newEngineBuilder() {
7387
public static void assertTStringEquals(String a, Object b) {
7488
Assert.assertEquals(Strings.fromJavaString(a), b);
7589
}
90+
91+
public static void assertThrows(Runnable test, Consumer<PolyglotException> exceptionVerifier) {
92+
try {
93+
test.run();
94+
fail("should have thrown");
95+
} catch (PolyglotException e) {
96+
exceptionVerifier.accept(e);
97+
}
98+
}
99+
100+
public static void assertThrows(Runnable test, JSErrorType expectedJSError) {
101+
try {
102+
test.run();
103+
fail("should have thrown " + expectedJSError.name());
104+
} catch (PolyglotException e) {
105+
assertTrue(e.isGuestException());
106+
assertThat(e.getMessage(), startsWith(expectedJSError.name()));
107+
}
108+
}
76109
}

0 commit comments

Comments
 (0)