diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java index 5cde6e3a640..2db5c8c976a 100644 --- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java +++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java @@ -246,6 +246,8 @@ public class Parser extends AbstractParser { private static final String MESSAGE_EXPECTED_OPERAND = "expected.operand"; private static final String MESSAGE_PROPERTY_REDEFINITON = "property.redefinition"; + private static final String MODULE = "module"; + /** Current env. */ private final ScriptEnvironment env; @@ -276,6 +278,8 @@ public class Parser extends AbstractParser { public static final boolean PROFILE_PARSING = Options.getBooleanProperty("parser.profiling", false); public static final boolean PROFILE_PARSING_PRINT = Options.getBooleanProperty("parser.profiling.print", true); + private static final List EMPTY_LIST = new ArrayList<>(); + /** * Constructor * @@ -450,7 +454,7 @@ public FunctionNode parseModule(final String moduleName, final int startPos, fin scanFirstToken(); - return module(moduleName); + return module(moduleName, false); } catch (final Exception e) { handleParseException(e); @@ -3602,6 +3606,7 @@ private void debuggerStatement() { * RegularExpressionLiteral * TemplateLiteral * CoverParenthesizedExpressionAndArrowParameterList + * ModuleBlockExpression * * CoverParenthesizedExpressionAndArrowParameterList : * ( Expression ) @@ -3625,10 +3630,23 @@ private Expression primaryExpression(boolean yield, boolean await) { markThis(); return new IdentNode(primaryToken, finish, name).setIsThis(); case IDENT: + // mimic code from AbstractParser.getIdent() + final long identToken = token; + String identString = (String) getValue(identToken); + + if (identString.equals(MODULE) && lookahead().equals(LBRACE)) { + nextOrEOL(); + expect(LBRACE); + + return module(source.getName() + "#L" + line, true); + } + final IdentNode ident = identifierReference(yield, await); + if (ident == null) { break; } + return detectSpecialProperty(ident); case NON_OCTAL_DECIMAL: if (isStrictMode) { @@ -6298,20 +6316,23 @@ private void addTemplateLiteralString(final ArrayList rawStrings, fi * ModuleItemList * */ - private FunctionNode module(final String moduleName) { + private FunctionNode module(final String moduleName, boolean moduleBlock) { // Make a pseudo-token for the script holding its start and length. int functionStart = Math.min(Token.descPosition(Token.withDelimiter(token)), finish); final long functionToken = Token.toDesc(FUNCTION, functionStart, source.getLength() - functionStart); final int functionLine = line; final Scope moduleScope = Scope.createModule(); - final IdentNode ident = null; + + final IdentNode ident = moduleBlock ? new IdentNode(functionToken, finish, moduleName) : null; + final ParserContextFunctionNode script = createParserContextFunctionNode( ident, functionToken, - FunctionNode.IS_MODULE, + moduleBlock ? FunctionNode.IS_MODULE_BLOCK : FunctionNode.IS_MODULE, functionLine, Collections. emptyList(), 0, moduleScope); + script.setInternalName(moduleName); lc.push(script); @@ -6320,7 +6341,7 @@ private FunctionNode module(final String moduleName) { functionDeclarations = new ArrayList<>(); try { - moduleBody(module); + moduleBody(module, moduleBlock); // Insert a synthetic yield before the module body but after any function declarations. long yieldToken = Token.toDesc(YIELD, functionStart, 0); @@ -6329,7 +6350,10 @@ private FunctionNode module(final String moduleName) { addFunctionDeclarations(script); } finally { - functionDeclarations = null; + + // module blocks expect an empty list otherwise evaluating the code fails + functionDeclarations = moduleBlock ? Collections.emptyList() : null; + restoreBlock(body); lc.pop(script); } @@ -6338,7 +6362,11 @@ private FunctionNode module(final String moduleName) { final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC | Block.IS_BODY | Block.IS_MODULE_BODY, body.getScope(), body.getStatements()); script.setLastToken(token); - expect(EOF); + if (moduleBlock) { + expect(RBRACE); + } else { + expect(EOF); + } script.setModule(module.createModule()); return createFunctionNode(script, functionToken, ident, functionLine, programBody); @@ -6361,11 +6389,15 @@ private FunctionNode module(final String moduleName) { * StatementListItem * */ - private void moduleBody(ParserContextModuleNode module) { - loop: while (type != EOF) { + private void moduleBody(ParserContextModuleNode module, boolean moduleBlock) { + TokenType endModuleToken = moduleBlock ? RBRACE : EOF; + + loop: while (type != endModuleToken) { switch (type) { case EOF: break loop; + case RBRACE: + break loop; case EXPORT: exportDeclaration(module); break; diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/FunctionNode.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/FunctionNode.java index c18ad87484a..555ea6e5a39 100644 --- a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/FunctionNode.java +++ b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/ir/FunctionNode.java @@ -238,6 +238,9 @@ public final class FunctionNode extends LexicalContextExpression implements Flag /** Is this function a class field initializer? */ public static final int IS_CLASS_FIELD_INITIALIZER = 1 << 30; + /** Is this function a module block? */ + public static final int IS_MODULE_BLOCK = 1 << 31; + /** * Constructor * @@ -787,4 +790,8 @@ public boolean needsSuper() { public boolean isClassFieldInitializer() { return getFlag(IS_CLASS_FIELD_INITIALIZER); } + + public boolean isModuleBlock() { + return getFlag(IS_MODULE_BLOCK); + } } diff --git a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java index fec2f12e2ce..662ca4282c4 100644 --- a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java +++ b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSEvaluator.java @@ -84,6 +84,7 @@ import com.oracle.truffle.js.nodes.function.EvalNode; import com.oracle.truffle.js.nodes.function.FunctionRootNode; import com.oracle.truffle.js.nodes.function.JSBuiltin; +import com.oracle.truffle.js.nodes.module.ModuleBlockNode; import com.oracle.truffle.js.nodes.promise.NewPromiseCapabilityNode; import com.oracle.truffle.js.nodes.promise.PerformPromiseThenNode; import com.oracle.truffle.js.parser.date.DateParser; @@ -133,6 +134,13 @@ public ScriptNode parseEval(JSContext context, Node lastNode, Source source) { return parseEval(context, lastNode, source, false, null); } + @Override + public JavaScriptNode parseModuleBlock(JSContext context, Source source) { + NodeFactory nodeFactory = NodeFactory.getInstance(context); + + return JavaScriptTranslator.translateModuleBlock(nodeFactory, context, source); + } + /** * Evaluate Function(parameterList, body). */ @@ -370,6 +378,19 @@ private static JSModuleRecord hostResolveImportedModule(JSModuleRecord referenci return referencingModule.getModuleLoader().resolveImportedModule(referencingModule, specifier); } + @Override + public JSModuleRecord hostResolveImportedModuleBlock(JSContext context, + ScriptOrModule referencingScriptOrModule, JSModuleRecord moduleBlock, DynamicObject specifier) { + JSModuleLoader moduleLoader = ((JSModuleRecord) referencingScriptOrModule).getModuleLoader(); + return moduleLoader.resolveImportedModuleBlock(moduleBlock, specifier); + } + + @Override + public JSModuleRecord hostResolveImportedModule(JSContext context, ScriptOrModule referencingScriptOrModule, DynamicObject moduleBlock, Source source) { + JSModuleLoader moduleLoader = ((JSModuleRecord) referencingScriptOrModule).getModuleLoader(); + return moduleLoader.resolveImportedModuleBlock(source, moduleBlock); + } + Collection getExportedNames(JSModuleRecord moduleRecord) { return getExportedNames(moduleRecord, new HashSet<>()); } diff --git a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSTranslator.java b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSTranslator.java index a2000061a67..f2c9dd295e6 100644 --- a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSTranslator.java +++ b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/GraalJSTranslator.java @@ -374,7 +374,7 @@ public JavaScriptNode enterFunctionNode(FunctionNode functionNode) { List declarations; if (functionMode) { declarations = functionEnvInit(functionNode); - } else if (functionNode.isModule()) { + } else if (functionNode.isModule() || functionNode.isModuleBlock()) { assert currentFunction.isGlobal(); declarations = Collections.emptyList(); } else { @@ -399,6 +399,10 @@ public JavaScriptNode enterFunctionNode(FunctionNode functionNode) { functionRoot = createFunctionRoot(functionNode, functionData, currentFunction, body); + if (functionNode.isModuleBlock()) { + return factory.createModuleBlock(context, body, functionRoot.getName()); + } + if (isEval) { // force eager call target init for Function() code to avoid deopt at call site functionData.getCallTarget(); @@ -994,7 +998,7 @@ private void findSymbol(String varName) { if (!local) { markUsesAncestorScopeUntil(lastFunction, true); } - } else if (function.isModule() && isImport(varName)) { + } else if ((function.isModule() || function.isModuleBlock()) && isImport(varName)) { // needed for GetActiveScriptOrModule() if (!local) { markUsesAncestorScopeUntil(lastFunction, true); @@ -1267,7 +1271,7 @@ private List createTemporalDeadZoneInit(Block block) { } private void createResolveImports(FunctionNode functionNode, List declarations) { - assert functionNode.isModule(); + assert functionNode.isModule() || functionNode.isModuleBlock(); // Assert: all named exports from module are resolvable. for (ImportEntry importEntry : functionNode.getModule().getImportEntries()) { @@ -1275,7 +1279,7 @@ private void createResolveImports(FunctionNode functionNode, List readAttributes(Path path, String attributes, LinkOpti deleteFiles(allFilesArray); } } + + /** + * Data can be exchanged between different threads running isolated, share-nothing, Graal.js + * contexts. Java synchronization can be used to exchange data between them. + */ + @Test(timeout = 10000) + public void moduleBlockSimplePingPong() { + final BlockingQueue queue = new ArrayBlockingQueue<>(1024); + + SimpleProducer p = new SimpleProducer(queue); + SimpleConsumer c = new SimpleConsumer(queue); + + c.start(); + p.start(); + try { + p.join(); + c.join(); + } catch (InterruptedException e) { + throw new AssertionError(e); + } + assertEquals(p.sent, 128); + assertEquals(c.received, 128); + } + + static class SimpleProducer extends Thread { + + private int sent; + private final BlockingQueue queue; + + SimpleProducer(BlockingQueue queue) { + this.queue = queue; + } + + @Override + public void run() { + Context cx = JSTest.newContextBuilder().allowHostAccess(HostAccess.ALL).option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").option(JSContextOptions.MODULE_BLOCKS_NAME, + "true").option(JSContextOptions.EXPERIMENTAL_MODULE_BLOCK_SERIALIZATION_API, + "true").build(); + cx.getBindings("js").putMember("queue", queue); + try { + sent = cx.eval("js", " var sent = 127;" + + "var moduleBlock = module { export var test = 128; };" + + "var moduleString = ModuleBlock.prototype.serialize(moduleBlock);" + + " queue.put(moduleString);" + + "++sent;").asInt(); + } finally { + cx.close(); + } + } + + } + + class SimpleConsumer extends Thread { + + private int received; + private final BlockingQueue queue; + + SimpleConsumer(BlockingQueue queue) { + this.queue = queue; + } + + @Override + public void run() { + Context cx = JSTest.newContextBuilder().allowHostAccess(HostAccess.ALL).option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").option(JSContextOptions.MODULE_BLOCKS_NAME, + "true").option(JSContextOptions.EXPERIMENTAL_MODULE_BLOCK_SERIALIZATION_API, + "true").build(); + cx.getBindings("js").putMember("queue", queue); + try { + received = cx.eval("js", "var received = 0;" + + " var moduleString = queue.take();" + + " var module = ModuleBlock.prototype.deserialize(moduleString);" + + "module.test;").asInt(); + } finally { + cx.close(); + } + } + } + + /** + * Data can be exchanged between different threads running isolated, share-nothing, Graal.js + * contexts. Java synchronization can be used to exchange data between them. + */ + @Test(timeout = 10000) + public void moduleBlockFibonacciPingPong() { + final BlockingQueue queue = new ArrayBlockingQueue<>(1024); + + Producer p = new Producer(queue); + Consumer c = new Consumer(queue); + + c.start(); + p.start(); + try { + p.join(); + c.join(); + } catch (InterruptedException e) { + throw new AssertionError(e); + } + assertEquals(p.result, 10946); + assertEquals(c.result, 10946); + } + + class Producer extends Thread { + + private int result; + private final BlockingQueue queue; + + Producer(BlockingQueue queue) { + this.queue = queue; + } + + @Override + public void run() { + Context cx = JSTest.newContextBuilder().allowHostAccess(HostAccess.ALL).option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").option(JSContextOptions.MODULE_BLOCKS_NAME, + "true").option(JSContextOptions.EXPERIMENTAL_MODULE_BLOCK_SERIALIZATION_API, + "true").build(); + cx.getBindings("js").putMember("queue", queue); + + try { + result = cx.eval("js", "var moduleBlock = module { export function fib(N) { " + + "var a = 1, b = 0, temp;" + + "while(N>=0) { temp = a; a = a + b; b = temp; N--; } return b; } };" + + "var moduleString = ModuleBlock.prototype.serialize(moduleBlock);" + "queue.put(moduleString);" + + "queue.take();").asInt(); + } finally { + cx.close(); + } + } + } + + class Consumer extends Thread { + private int result; + private final BlockingQueue queue; + + Consumer(BlockingQueue queue) { + this.queue = queue; + } + + @Override + public void run() { + Context cx = JSTest.newContextBuilder().allowHostAccess(HostAccess.ALL).option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").option(JSContextOptions.MODULE_BLOCKS_NAME, + "true").option(JSContextOptions.EXPERIMENTAL_MODULE_BLOCK_SERIALIZATION_API, + "true").build(); + cx.getBindings("js").putMember("queue", queue); + + try { + result = cx.eval("js", "var number = 20;" + "var moduleString = queue.take();" + "var module = ModuleBlock.prototype.deserialize(moduleString);" + + "var fibonacci = module.fib(number);" + + "queue.put(fibonacci); fibonacci;").asInt(); + } finally { + cx.close(); + } + } + } } diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModule.js b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModule.js new file mode 100644 index 00000000000..7ab724d01e2 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModule.js @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +const N = 100000; // datapoints +const K = 7; // cluster +const SIZE = 600 // max data size + +const N_EXP = 20; // 20 runs + +const clusterX = new Array(K); +const clusterY = new Array(K); + +const dataPointsX = new Array(N); +const dataPointsY = new Array(N); +const dataPointsCluster = new Array(N); + +function computeDist(x1, y1, x2, y2) { + let dx = x1-x2; + let dy = y1-y2; + + return dx * dx + dy * dy; +} + +function getClosestCluster(x,y) { + let minCluster=-1; + let minDist = Number.MAX_VALUE; // set min to max dist + + for (let i = 0; i < K; i++) { + let dist = computeDist(x,y,clusterX[i],clusterY[i]); + + if (dist < minDist) { + minCluster=i; + minDist = dist; + } + } + + return minCluster; +} + +function computeCentroids() { + let sumX = new Array(K); + let sumY = new Array(K); + let sumN = new Array(K); + + for (let i = 0; i < N; i++) { + sumX[dataPointsCluster[i]] += dataPointsX[i]; + sumY[dataPointsCluster[i]] += dataPointsY[i]; + sumN[dataPointsCluster[i]]++; + } + + for (let i = 0; i < K; i++) { + if (sumN[i] != 0) { + clusterX[i] = sumX[i] / sumN[i]; + clusterY[i] = sumY[i] / sumN[i]; + } + } +} + +function doNewClustering() { + let stable = true; + + for (let i = 0; i < N; i++) { + let closestCluster = getClosestCluster(dataPointsX[i],dataPointsY[i]); + + if (stable && dataPointsCluster[i] != closestCluster) { + stable = false; + } + + dataPointsCluster[i] = closestCluster; + } + + return stable; +} + +function doInitialClustering() { + for (let i = 0; i < N; i++) { + dataPointsCluster[i] = Math.floor(Math.random() * K); + } +} + +export function createRandomData() { + for (let i = 0; i < N; i++) { + dataPointsX[i] = Math.floor(Math.random() * SIZE); + dataPointsY[i] = Math.floor(Math.random() * SIZE); + } +} + +export function cluster() { + doInitialClustering(); + + computeCentroids(); + + let stable = false; + + while (!stable) { + stable = doNewClustering(); + computeCentroids(); + } +} diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModuleBlock.js b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModuleBlock.js new file mode 100644 index 00000000000..8498a58ccd6 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModuleBlock.js @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2021, 2021, 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. + */ + +(async function() { + + var kMeans = module { + + const N = 100000; // datapoints + const K = 7; // cluster + const SIZE = 600 // max data size + + const N_EXP = 20; // 20 runs + + const clusterX = new Array(K); + const clusterY = new Array(K); + + const dataPointsX = new Array(N); + const dataPointsY = new Array(N); + const dataPointsCluster = new Array(N); + + function computeDist(x1, y1, x2, y2) { + let dx = x1-x2; + let dy = y1-y2; + + return dx * dx + dy * dy; + } + + function getClosestCluster(x,y) { + let minCluster=-1; + let minDist = Number.MAX_VALUE; // set min to max dist + + for (let i = 0; i < K; i++) { + let dist = computeDist(x,y,clusterX[i],clusterY[i]); + + if (dist < minDist) { + minCluster=i; + minDist = dist; + } + } + + return minCluster; + } + + function computeCentroids() { + let sumX = new Array(K); + let sumY = new Array(K); + let sumN = new Array(K); + + for (let i = 0; i < N; i++) { + sumX[dataPointsCluster[i]] += dataPointsX[i]; + sumY[dataPointsCluster[i]] += dataPointsY[i]; + sumN[dataPointsCluster[i]]++; + } + + for (let i = 0; i < K; i++) { + if (sumN[i] != 0) { + clusterX[i] = sumX[i] / sumN[i]; + clusterY[i] = sumY[i] / sumN[i]; + } + } + } + + function doNewClustering() { + let stable = true; + + for (let i = 0; i < N; i++) { + let closestCluster = getClosestCluster(dataPointsX[i],dataPointsY[i]); + + if (stable && dataPointsCluster[i] != closestCluster) { + stable = false; + } + + dataPointsCluster[i] = closestCluster; + } + + return stable; + } + + function doInitialClustering() { + for (let i = 0; i < N; i++) { + dataPointsCluster[i] = Math.floor(Math.random() * K); + } + } + + function createRandomData() { + for (let i = 0; i < N; i++) { + dataPointsX[i] = Math.floor(Math.random() * SIZE); + dataPointsY[i] = Math.floor(Math.random() * SIZE); + } + } + + function cluster() { + doInitialClustering(); + + computeCentroids(); + + let stable = false; + + while (!stable) { + stable = doNewClustering(); + computeCentroids(); + } + } + + createRandomData(); + cluster(); + }; + + return await import(kMeans); +})(); diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModuleImport.js b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModuleImport.js new file mode 100644 index 00000000000..54e44edb016 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModuleImport.js @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021, 2021, 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. + */ + +import * as module from 'kMeansModule.js'; + +module.createRandomData(); +module.cluster(); diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModuleModuleBlock.js b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModuleModuleBlock.js new file mode 100644 index 00000000000..6a8efee3260 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModuleModuleBlock.js @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2021, 2021, 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. + */ + +export var moduleBlock = (async function() { + + var kMeans = module { + + const N = 100000; // datapoints + const K = 7; // cluster + const SIZE = 600 // max data size + + const N_EXP = 20; // 20 runs + + const clusterX = new Array(K); + const clusterY = new Array(K); + + const dataPointsX = new Array(N); + const dataPointsY = new Array(N); + const dataPointsCluster = new Array(N); + + function computeDist(x1, y1, x2, y2) { + let dx = x1-x2; + let dy = y1-y2; + + return dx * dx + dy * dy; + } + + function getClosestCluster(x,y) { + let minCluster=-1; + let minDist = Number.MAX_VALUE; // set min to max dist + + for (let i = 0; i < K; i++) { + let dist = computeDist(x,y,clusterX[i],clusterY[i]); + + if (dist < minDist) { + minCluster=i; + minDist = dist; + } + } + + return minCluster; + } + + function computeCentroids() { + let sumX = new Array(K); + let sumY = new Array(K); + let sumN = new Array(K); + + for (let i = 0; i < N; i++) { + sumX[dataPointsCluster[i]] += dataPointsX[i]; + sumY[dataPointsCluster[i]] += dataPointsY[i]; + sumN[dataPointsCluster[i]]++; + } + + for (let i = 0; i < K; i++) { + if (sumN[i] != 0) { + clusterX[i] = sumX[i] / sumN[i]; + clusterY[i] = sumY[i] / sumN[i]; + } + } + } + + function doNewClustering() { + let stable = true; + + for (let i = 0; i < N; i++) { + let closestCluster = getClosestCluster(dataPointsX[i],dataPointsY[i]); + + if (stable && dataPointsCluster[i] != closestCluster) { + stable = false; + } + + dataPointsCluster[i] = closestCluster; + } + + return stable; + } + + function doInitialClustering() { + for (let i = 0; i < N; i++) { + dataPointsCluster[i] = Math.floor(Math.random() * K); + } + } + + function createRandomData() { + for (let i = 0; i < N; i++) { + dataPointsX[i] = Math.floor(Math.random() * SIZE); + dataPointsY[i] = Math.floor(Math.random() * SIZE); + } + } + + function cluster() { + doInitialClustering(); + + computeCentroids(); + + let running = false; + + while (!running) { + running = doNewClustering(); + computeCentroids(); + } + } + + createRandomData(); + cluster(); + }; + + return await import(kMeans); +}); diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModuleModuleBlockImport.js b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModuleModuleBlockImport.js new file mode 100644 index 00000000000..85d2d8a98a2 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModuleModuleBlockImport.js @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021, 2021, 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. + */ + +import * as module from 'kMeansModuleModuleBlock.js'; + +module.moduleBlock(); diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansRegular.js b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansRegular.js new file mode 100644 index 00000000000..4423d6a7ace --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansRegular.js @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +const N = 100000; // datapoints +const K = 7; // cluster +const SIZE = 600 // max data size + +const N_EXP = 20; // 20 runs + +const clusterX = new Array(K); +const clusterY = new Array(K); + +const dataPointsX = new Array(N); +const dataPointsY = new Array(N); +const dataPointsCluster = new Array(N); + +function computeDist(x1, y1, x2, y2) { + let dx = x1-x2; + let dy = y1-y2; + + return dx * dx + dy * dy; +} + +function getClosestCluster(x,y) { + let minCluster=-1; + let minDist = Number.MAX_VALUE; // set min to max dist + + for (let i = 0; i < K; i++) { + let dist = computeDist(x,y,clusterX[i],clusterY[i]); + + if (dist < minDist) { + minCluster=i; + minDist = dist; + } + } + + return minCluster; +} + +function computeCentroids() { + let sumX = new Array(K); + let sumY = new Array(K); + let sumN = new Array(K); + + for (let i = 0; i < N; i++) { + sumX[dataPointsCluster[i]] += dataPointsX[i]; + sumY[dataPointsCluster[i]] += dataPointsY[i]; + sumN[dataPointsCluster[i]]++; + } + + for (let i = 0; i < K; i++) { + if (sumN[i] != 0) { + clusterX[i] = sumX[i] / sumN[i]; + clusterY[i] = sumY[i] / sumN[i]; + } + } +} + +function doNewClustering() { + let stable = true; + + for (let i = 0; i < N; i++) { + let closestCluster = getClosestCluster(dataPointsX[i],dataPointsY[i]); + + if (stable && dataPointsCluster[i] != closestCluster) { + stable = false; + } + + dataPointsCluster[i] = closestCluster; + } + + return stable; +} + +function doInitialClustering() { + for (let i = 0; i < N; i++) { + dataPointsCluster[i] = Math.floor(Math.random() * K); + } +} + +function createRandomData() { + for (let i = 0; i < N; i++) { + dataPointsX[i] = Math.floor(Math.random() * SIZE); + dataPointsY[i] = Math.floor(Math.random() * SIZE); + } +} + +function cluster() { + doInitialClustering(); + + computeCentroids(); + + let stable = false; + + while (!stable) { + stable = doNewClustering(); + computeCentroids(); + } +} + +createRandomData(); +cluster(); diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/toy/regular.js b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/toy/regular.js new file mode 100644 index 00000000000..ff0be296bd9 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/toy/regular.js @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2021, 2021, 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. + */ + + function simple() { + return 2+3; + } + + simple(); + \ No newline at end of file diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/toy/regularModuleBlock.js b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/toy/regularModuleBlock.js new file mode 100644 index 00000000000..819950aa362 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/toy/regularModuleBlock.js @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021, 2021, 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. + */ + + var simple = (async function() { + const moduleBlock = module { export var t = 3; }; + + return await import(moduleBlock); +})(); + +simple.then(value => value.t+2); diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockAsync.js b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockAsync.js new file mode 100644 index 00000000000..f1342873a7e --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockAsync.js @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2021, 2021, 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. + */ + +var test = (async function() { + var moduleBlockAsync = module { + function resolve() { + return new Promise(resolve => { + resolve(4); + }); + } + + async function asyncCall() { + return await resolve(); + } + + export var resolved = asyncCall(); + }; + + return await import(moduleBlockAsync); +})(); + + +var five = test.then( function(moduleBlock) { + return moduleBlock.resolved; +}).then(resolved => resolved+1); + +var eleven = test.then( function(moduleBlock) { + return moduleBlock.resolved; +}).then(resolved => resolved+7); + +var aLot = test.then( function(moduleBlock) { + return moduleBlock.resolved; +}).then(resolved => resolved+117); + +[aLot, five, eleven]; diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockComparison.js b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockComparison.js new file mode 100644 index 00000000000..3c6fd68c09b --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockComparison.js @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2021, 2021, 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. + */ + +(async function() { + let moduleBlock = module { + export let y = 1; + }; + + let moduleExports = await import(moduleBlock); + console.assert(moduleExports.y === 1, "Module block import/export failed."); + + console.assert(await import(moduleBlock) === moduleExports, "Not equal."); +})(); + +(async function() { + const arr = new Array(2); + + for (let i = 0; i < 2; i++) { + arr[i] = module {}; + } + + console.assert(arr[0] !== arr[1], "Different module blocks are the same."); + console.assert(await import(arr[0]) !== await import(arr[1]), "Different imported module blocks are the same."); +})(); + +(async function() { + const m1 = module {}; + const m2 = m1; + + console.assert(await import(m1) === await import(m2), "The same module block imported twice is not the same."); +})(); + +var moduleTest = (async function() { + const moduleBlock = module { }; + + return await import(moduleBlock); +})(); + +[moduleTest.then(v=>121), moduleTest.then(v=>5), moduleTest.then(v=>11)]; + +// This test can be conducted as soon as the realms proposal: https://github.com/tc39/proposal-realms is implemented +/* + +(async function() { + let moduleBlock = module { + export let o = Object; + }; + + let m = await import(moduleBlock); + console.assert(m.o === Object, "O export is not an object."); + + let r1 = new Realm(); + let m1 = await r1.import(moduleBlock); + console.assert(m1.o === r1.globalThis.Object, "Realm o export is not an object."); + console.assert(m1.o !== Object, "Realm o export is old realm object."); + console.assert(m.o !== m1.o, "Both o's are equal."); +})(); + +*/ diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockFunctionExportTestMimic.js b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockFunctionExportTestMimic.js new file mode 100644 index 00000000000..1216095a6a5 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockFunctionExportTestMimic.js @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2021, 2021, 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. + */ +import * as module from 'functionexportmodule.js'; // import everything that the module exports + +// 3 module blocks mimicking the function export test, resulting in 3 promise +// objects with the desired values: 121, 5, 11 + +var squareTest = (async function() { + const moduleBlock = module { export var t = 11; }; + + return await import(moduleBlock); +})(); + +var diagTest = (async function() { + const moduleBlock = module { export var x = 3; + export var y = 4; }; + + return await import(moduleBlock); +})(); + +var sqrtTest = (async function() { + const moduleBlock = module { export var v = 121; }; + + return await import(moduleBlock); +})(); + +var sq = squareTest.then(function(value) { return module.square(value.t); }); + +var dg = diagTest.then(value => module.diag(value.x, value.y)); +var st = sqrtTest.then(value => module.sqrt(value.v)); + +[sq, dg, st]; diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockPrototype.js b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockPrototype.js new file mode 100644 index 00000000000..dcaeb262538 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockPrototype.js @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2021, 2021, 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. + */ +import * as module from 'functionexportmodule.js'; // import everything that the module exports + +// 3 module blocks mimicking the function export test, resulting in 3 promise +// objects with the desired values: 121, 5, 11 + +var squareTest = (async function() { + const moduleBlock = module { export var t = 11; }; + + return await import(moduleBlock); +})(); + +var diagTest = (async function() { + const moduleBlock = module { export var x = 3; + export var y = 4; }; + + return await import(moduleBlock); +})(); + +var sqrtTest = (async function() { + const moduleBlock = module { export var v = 121; }; + + return await import(moduleBlock); +})(); + +var moduleBlock = module { }; + +var sq; +var dg; +var st; + +if (moduleBlock instanceof ModuleBlock) { + sq = squareTest.then(function(value) { return module.square(value.t); }); +} else { + sq = 0; +} + +if (Object.getPrototypeOf(moduleBlock) === ModuleBlock.prototype) { + dg = diagTest.then(value => module.diag(value.x, value.y)); +} else { + dg = 0; +} + +if (moduleBlock.constructor.prototype === Object.prototype) { + st = sqrtTest.then(value => module.sqrt(value.v)); +} else { + st = 0; +} + +[sq, dg, st]; diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockSerialize.js b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockSerialize.js new file mode 100644 index 00000000000..29db9054cfb --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockSerialize.js @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2021, 2021, 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. + */ + +import * as modules from 'moduleBlockSerializeModule.js'; + +console.log(modules.moduleBlock); + +var tester = ModuleBlock.prototype.deserialize(modules.moduleBlock); + +var isIt = tester.test; + +console.log(isIt); + +[121,5,11]; \ No newline at end of file diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockSerializeModule.js b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockSerializeModule.js new file mode 100644 index 00000000000..5e7201e7900 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockSerializeModule.js @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021, 2021, 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. + */ + +var moduleTest = module { export var test = 5; }; + +var test = ModuleBlock.prototype.serialize(moduleTest); + +export var moduleBlock = ModuleBlock.prototype.serialize(moduleTest); diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockToString.js b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockToString.js new file mode 100644 index 00000000000..304b289200e --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockToString.js @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2021, 2021, 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. + */ + +var moduleBlockOne = module { export var test = 42; }; + +var one = 0; +var two = 0; + +if (moduleBlockOne.toString() === "module { export var test = 42; }") { + one = 5; +} else { + one = 0; +} + +console.log(ModuleBlock.prototype); + +if (ModuleBlock.prototype.toString() === "ModuleBlock.prototype") { + two = 121; +} else { + two = 0; +} + +[two,one,11]; diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java index 5550307bc70..e57060069a6 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ConstructorBuiltins.java @@ -322,6 +322,7 @@ public enum Constructor implements BuiltinEnum { // --- not new.target-capable below --- TypedArray(0), Symbol(0), + ModuleBlock(0), // non-standard (Nashorn) extensions JSAdapter(1), @@ -624,6 +625,8 @@ protected Object createNode(JSContext context, JSBuiltin builtin, boolean constr ? ConstructWebAssemblyTableNodeGen.create(context, builtin, true, args().newTarget().fixedArgs(1).createArgumentNodes(context)) : ConstructWebAssemblyTableNodeGen.create(context, builtin, false, args().function().fixedArgs(1).createArgumentNodes(context))) : createCallRequiresNew(context, builtin); + case ModuleBlock: + throw Errors.createTypeErrorNotAConstructor(builtin.getName(), context); } return null; diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DebugBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DebugBuiltins.java index bed233a8d90..63f42850bcf 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DebugBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/DebugBuiltins.java @@ -637,6 +637,16 @@ public JSModuleRecord resolveImportedModule(ScriptOrModule referencingModule, St public JSModuleRecord loadModule(Source moduleSource) { throw new UnsupportedOperationException(); } + + @Override + public JSModuleRecord resolveImportedModuleBlock(Source source, DynamicObject specifier) { + throw new UnsupportedOperationException(); + } + + @Override + public JSModuleRecord resolveImportedModuleBlock(JSModuleRecord moduleBlock, DynamicObject specifier) { + throw new UnsupportedOperationException(); + } }; JSModuleRecord module = moduleLoader.resolveImportedModule(null, name); JSRealm realm = context.getRealm(); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/GlobalBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/GlobalBuiltins.java index 3190dc95e04..fa95f099ee4 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/GlobalBuiltins.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/GlobalBuiltins.java @@ -80,6 +80,7 @@ import com.oracle.truffle.api.library.CachedLibrary; import com.oracle.truffle.api.nodes.IndirectCallNode; import com.oracle.truffle.api.object.DynamicObject; +import com.oracle.truffle.api.object.DynamicObjectLibrary; import com.oracle.truffle.api.profiles.BranchProfile; import com.oracle.truffle.api.profiles.ConditionProfile; import com.oracle.truffle.api.source.Source; @@ -110,6 +111,7 @@ import com.oracle.truffle.js.nodes.JavaScriptNode; import com.oracle.truffle.js.nodes.ScriptNode; import com.oracle.truffle.js.nodes.access.JSConstantNode; +import com.oracle.truffle.js.nodes.access.PropertyGetNode; import com.oracle.truffle.js.nodes.cast.JSToDoubleNode; import com.oracle.truffle.js.nodes.cast.JSToInt32Node; import com.oracle.truffle.js.nodes.cast.JSToNumberNode; @@ -147,6 +149,10 @@ import com.oracle.truffle.js.runtime.objects.PropertyProxy; import com.oracle.truffle.js.runtime.objects.Undefined; +import com.oracle.truffle.api.object.DynamicObject; +import com.oracle.truffle.api.object.DynamicObjectLibrary; +import com.oracle.truffle.js.nodes.module.ModuleBlockNode; + /** * Contains builtins for the global object. */ @@ -215,6 +221,7 @@ protected Object createNode(JSContext context, JSBuiltin builtin, boolean constr return JSGlobalDecodeURINodeGen.create(context, builtin, false, args().fixedArgs(1).createArgumentNodes(context)); case eval: return JSGlobalIndirectEvalNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context)); + case escape: return JSGlobalUnEscapeNodeGen.create(context, builtin, false, args().fixedArgs(1).createArgumentNodes(context)); case unescape: diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ModuleBlockPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ModuleBlockPrototypeBuiltins.java new file mode 100644 index 00000000000..07000108185 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ModuleBlockPrototypeBuiltins.java @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2021, 2021, 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.builtins; + +import java.nio.charset.StandardCharsets; + +import com.oracle.truffle.api.Truffle; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.object.DynamicObject; +import com.oracle.truffle.api.object.DynamicObjectLibrary; +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.js.builtins.ModuleBlockPrototypeBuiltinsFactory.JSGlobalDeserializeNodeGen; +import com.oracle.truffle.js.builtins.ModuleBlockPrototypeBuiltinsFactory.JSGlobalSerializeNodeGen; +import com.oracle.truffle.js.builtins.ModuleBlockPrototypeBuiltinsFactory.JSModuleBlockToStringNodeGen; +import com.oracle.truffle.js.lang.JavaScriptLanguage; +import com.oracle.truffle.js.nodes.JavaScriptNode; +import com.oracle.truffle.js.nodes.access.PropertyGetNode; +import com.oracle.truffle.js.nodes.function.JSBuiltin; +import com.oracle.truffle.js.nodes.function.JSBuiltinNode; +import com.oracle.truffle.js.nodes.module.ModuleBlockNode; +import com.oracle.truffle.js.runtime.Errors; +import com.oracle.truffle.js.runtime.JSContext; +import com.oracle.truffle.js.runtime.JSRealm; +import com.oracle.truffle.js.runtime.array.TypedArray; +import com.oracle.truffle.js.runtime.builtins.BuiltinEnum; +import com.oracle.truffle.js.runtime.builtins.JSArrayBuffer; +import com.oracle.truffle.js.runtime.builtins.JSModuleBlock; +import com.oracle.truffle.js.runtime.objects.DefaultESModuleLoader; +import com.oracle.truffle.js.runtime.objects.JSModuleRecord; +import com.oracle.truffle.js.runtime.objects.JSObjectUtil; + +/** + * Contains builtins for %ModuleBlock%.prototype. + */ +public class ModuleBlockPrototypeBuiltins extends JSBuiltinsContainer.SwitchEnum { + + public static final JSBuiltinsContainer BUILTINS = new ModuleBlockPrototypeBuiltins(); + + protected ModuleBlockPrototypeBuiltins() { + super(JSModuleBlock.PROTOTYPE_NAME, ModuleBlockPrototype.class); + } + + public enum ModuleBlockPrototype implements BuiltinEnum { + toString(0), + // ModuleBlock methods + serialize(1), + deserialize(1); + + private final int length; + + ModuleBlockPrototype(int length) { + this.length = length; + } + + @Override + public int getLength() { + return length; + } + } + + @Override + protected Object createNode(JSContext context, JSBuiltin builtin, boolean construct, boolean newTarget, ModuleBlockPrototype builtinEnum) { + switch (builtinEnum) { + case toString: + return JSModuleBlockToStringNodeGen.create(context, builtin, args().withThis().createArgumentNodes(context)); + case serialize: + return JSGlobalSerializeNodeGen.create(context, builtin, + args().fixedArgs(1).createArgumentNodes(context)); + case deserialize: + return JSGlobalDeserializeNodeGen.create(context, builtin, + args().fixedArgs(1).createArgumentNodes(context)); + } + return null; + } + + public abstract static class JSModuleBlockToStringNode extends JSBuiltinNode { + DynamicObject prototype; + + public JSModuleBlockToStringNode(JSContext context, JSBuiltin builtin) { + super(context, builtin); + + prototype = context.getRealm().getModuleBlockPrototype(); + } + + @Specialization(guards = "isJSOrdinaryObject(thisModuleBlock)") + protected String doOperation(Object thisModuleBlock) { + // Type check, then check for hidden property body and return hidden property + // sourceText + if (JSObjectUtil.hasHiddenProperty((DynamicObject) thisModuleBlock, + ModuleBlockNode.getModuleBodyKey())) { + PropertyGetNode getSourceCode = PropertyGetNode.createGetHidden(ModuleBlockNode.getModuleSourceKey(), this.getContext()); + + Object sourceCode = getSourceCode.getValue(thisModuleBlock); + + return "module {" + sourceCode.toString() + " }"; + } else if (thisModuleBlock.equals(prototype)) { + return JSModuleBlock.PROTOTYPE_NAME; + } + + notJSModuleBlock(thisModuleBlock); + + return ""; + } + + @Specialization(guards = "!isJSOrdinaryObject(thisModuleBlock)") + protected static boolean notJSModuleBlock(Object thisModuleBlock) { + throw Errors.createTypeError("Not a module block"); + } + + } + + /** + * Implementation of Module Block serialize-method + */ + public abstract static class JSGlobalSerializeNode extends JSBuiltinNode { + + protected JSContext context_; + + protected JSGlobalSerializeNode(JSContext context, JSBuiltin builtin) { + super(context, builtin); + context_ = context; + } + + @Specialization(guards = "context_.isExperimentalModuleBlocks()") + protected String doOperation(Object value) { + assert value instanceof DynamicObject; + if (JSObjectUtil.hasHiddenProperty((DynamicObject) value, + ModuleBlockNode.getModuleBodyKey())) { + PropertyGetNode getSourceCode = PropertyGetNode.createGetHidden(ModuleBlockNode.getModuleSourceKey(), getContext()); + + Object sourceCode = getSourceCode.getValue(value); + + return sourceCode.toString(); + } + + Errors.createTypeError("Not a ModuleBlock"); + + return null; + } + } + + /** + * Implementation of Module Block deserialize-method + */ + public abstract static class JSGlobalDeserializeNode extends JSBuiltinNode { + + protected JSContext context_; + + protected JSGlobalDeserializeNode(JSContext context, JSBuiltin builtin) { + super(context, builtin); + context_ = context; + } + + @Specialization(guards = "context_.isExperimentalModuleBlocks()") + protected Object doOperation(Object value) { + assert value instanceof String; + + String sourceCode = (String) value; + + // turn from sourcecode string to module block via parsing and then translating + Source source = Source.newBuilder(JavaScriptLanguage.ID, sourceCode, "moduleBlock").build(); + + JSRealm realm = context_.getRealm(); + + JSModuleRecord moduleRecord = getContext().getEvaluator().parseModule(getContext(), source, DefaultESModuleLoader.create(context_.getRealm())); + + context_.getEvaluator().moduleInstantiation(realm, moduleRecord); + context_.getEvaluator().moduleEvaluation(realm, moduleRecord); + + DynamicObject dyn = context_.getEvaluator().getModuleNamespace(moduleRecord); + + return dyn; + } + } +} \ No newline at end of file diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/JSGuards.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/JSGuards.java index 26ceaab381c..546a5ff9b79 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/JSGuards.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/JSGuards.java @@ -60,6 +60,7 @@ import com.oracle.truffle.js.runtime.builtins.JSFinalizationRegistry; import com.oracle.truffle.js.runtime.builtins.JSFunction; import com.oracle.truffle.js.runtime.builtins.JSMap; +import com.oracle.truffle.js.runtime.builtins.JSModuleBlock; import com.oracle.truffle.js.runtime.builtins.JSModuleNamespace; import com.oracle.truffle.js.runtime.builtins.JSNumber; import com.oracle.truffle.js.runtime.builtins.JSObjectPrototype; @@ -473,4 +474,8 @@ public static boolean isArrayIndexLengthInRange(String str) { public static boolean hasOverloadedOperators(Object value) { return JSOverloadedOperatorsObject.hasOverloadedOperators(value); } + + public static boolean isJSModuleBlock(Object object) { + return JSModuleBlock.isJSModuleBlock(object); + } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/NodeFactory.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/NodeFactory.java index d0499bda653..8f6e6054264 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/NodeFactory.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/NodeFactory.java @@ -203,6 +203,7 @@ import com.oracle.truffle.js.nodes.function.NewTargetRootNode; import com.oracle.truffle.js.nodes.function.SpreadArgumentNode; import com.oracle.truffle.js.nodes.module.ImportMetaNode; +import com.oracle.truffle.js.nodes.module.ModuleBlockNode; import com.oracle.truffle.js.nodes.module.ReadImportBindingNode; import com.oracle.truffle.js.nodes.module.ResolveNamedImportNode; import com.oracle.truffle.js.nodes.module.ResolveStarImportNode; @@ -1183,6 +1184,10 @@ public JavaScriptNode createDebugVarWrapper(String varName, JavaScriptNode defau return new DebugScopeVarWrapperNode(varName, defaultDelegate, dynamicScope, scopeAccessNode); } + public JavaScriptNode createModuleBlock(JSContext context, JavaScriptNode body, String moduleBlockSourceName) { + return ModuleBlockNode.create(context, body, moduleBlockSourceName); + } + // ##### public static NodeFactory getDefaultInstance() { diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ModuleBlockNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ModuleBlockNode.java new file mode 100644 index 00000000000..3359a66d896 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ModuleBlockNode.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.nodes.module; + +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.object.DynamicObject; +import com.oracle.truffle.api.object.HiddenKey; +import com.oracle.truffle.js.nodes.JavaScriptNode; +import com.oracle.truffle.js.nodes.access.CreateObjectNode; +import com.oracle.truffle.js.nodes.access.PropertySetNode; +import com.oracle.truffle.js.runtime.JSContext; + +public class ModuleBlockNode extends JavaScriptNode { + + public static final String TYPE_NAME = "moduleBlock"; + + static final HiddenKey SOURCE_KEY = new HiddenKey("SourceText"); + static final HiddenKey MODULE_BODY_KEY = new HiddenKey("ModuleBlockBody"); + static final HiddenKey HOST_DEFINED_SLOT = new HiddenKey("HostDefinedSlot"); + + private final JSContext context; + private final String moduleBlockSourceName; + + @Child private JavaScriptNode body; + @Child private CreateObjectNode.CreateObjectWithPrototypeNode moduleBlockCreateNode; + @Child private PropertySetNode setHostDefinedSlot; + @Child private PropertySetNode setModuleBlockBody; + @Child private PropertySetNode setSourceText; + + private ModuleBlockNode(JSContext context, JavaScriptNode body, String moduleBlockSourceName) { + this.context = context; + this.body = body; + this.moduleBlockSourceName = moduleBlockSourceName; + + // for step 1 of runtime semantics + this.moduleBlockCreateNode = CreateObjectNode.createOrdinaryWithPrototype(context); + // prepare setting steps for runtime semantic steps 2,3,4 + this.setSourceText = PropertySetNode.createSetHidden(SOURCE_KEY, context); + this.setModuleBlockBody = PropertySetNode.createSetHidden(MODULE_BODY_KEY, context); + this.setHostDefinedSlot = PropertySetNode.createSetHidden(HOST_DEFINED_SLOT, context); + + } + + public static ModuleBlockNode create(JSContext context, JavaScriptNode body, String moduleBlockSourceName) { + return new ModuleBlockNode(context, body, moduleBlockSourceName); + } + + public static HiddenKey getModuleSourceKey() { + return SOURCE_KEY; + } + + public static HiddenKey getModuleBodyKey() { + return MODULE_BODY_KEY; + } + + public static HiddenKey getHostDefinedSlotKey() { + return HOST_DEFINED_SLOT; + } + + @Override + public Object execute(VirtualFrame frame) { + + // 1 create + DynamicObject newModuleBlockInstance = moduleBlockCreateNode.execute(context.getRealm().getModuleBlockPrototype()); + + // 2 set source text to the source text matched by ModuleBlockExpression + setSourceText.setValue(newModuleBlockInstance, body.getSourceSection().getCharacters()); + // 3 specification says to parse now but it is already parsed and also will be parsed + // when imported + // DO NOTHING + + // 4 store text + setModuleBlockBody.setValue(newModuleBlockInstance, body); + + // 5 perform hostInitializeModuleBlock(myNewInstance) + hostInitializeModuleBlock(newModuleBlockInstance); + + setHostDefinedSlot.setValue(newModuleBlockInstance, moduleBlockSourceName); + + // 6 return module Block + return newModuleBlockInstance; + } + + /** + * Not implemented yet as no specification is set on it yet. + * + * @param myNewInstance module object + */ + private void hostInitializeModuleBlock(DynamicObject myNewInstance) { + + } + +} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java index 853107b611e..8a3896c1990 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/promise/ImportCallNode.java @@ -50,7 +50,11 @@ import com.oracle.truffle.api.instrumentation.Tag; import com.oracle.truffle.api.interop.InteropLibrary; import com.oracle.truffle.api.object.DynamicObject; +import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.js.lang.JavaScriptLanguage; import com.oracle.truffle.js.nodes.JavaScriptNode; +import com.oracle.truffle.js.nodes.access.JSHasPropertyNode; +import com.oracle.truffle.js.nodes.access.PropertyGetNode; import com.oracle.truffle.js.nodes.arguments.AccessIndexedArgumentNode; import com.oracle.truffle.js.nodes.cast.JSToStringNode; import com.oracle.truffle.js.nodes.control.TryCatchNode; @@ -67,6 +71,8 @@ import com.oracle.truffle.js.runtime.builtins.JSFunctionData; import com.oracle.truffle.js.runtime.builtins.JSPromise; import com.oracle.truffle.js.runtime.objects.JSModuleRecord; +import com.oracle.truffle.js.runtime.objects.JSObject; +import com.oracle.truffle.js.runtime.objects.JSObjectUtil; import com.oracle.truffle.js.runtime.objects.PromiseCapabilityRecord; import com.oracle.truffle.js.runtime.objects.PromiseReactionRecord; import com.oracle.truffle.js.runtime.objects.ScriptOrModule; @@ -74,6 +80,9 @@ import com.oracle.truffle.js.runtime.util.Pair; import com.oracle.truffle.js.runtime.util.Triple; +import com.oracle.truffle.api.object.DynamicObjectLibrary; +import com.oracle.truffle.js.nodes.module.ModuleBlockNode; + /** * Represents the import call expression syntax: {@code import(specifier)}. */ @@ -89,6 +98,9 @@ public class ImportCallNode extends JavaScriptNode { @Child private TryCatchNode.GetErrorObjectNode getErrorObjectNode; @Child private InteropLibrary exceptions; + // read the hidden key with @ child + @Child private PropertyGetNode body; + private final JSContext context; protected ImportCallNode(JSContext context, JavaScriptNode argRefNode, JavaScriptNode activeScriptOrModuleNode) { @@ -109,6 +121,26 @@ public Object execute(VirtualFrame frame) { Object referencingScriptOrModule = getActiveScriptOrModule(frame); Object specifier = argRefNode.execute(frame); String specifierString; + + if (specifier instanceof DynamicObject && JSObjectUtil.hasHiddenProperty((DynamicObject) specifier, + ModuleBlockNode.getModuleBodyKey())) { + // read the hidden key from 'specifier' + this.body = PropertyGetNode.createGetHidden(ModuleBlockNode.getModuleBodyKey(), this.context); + PropertyGetNode getSourceCode = PropertyGetNode.createGetHidden(ModuleBlockNode.getModuleSourceKey(), this.context); + PropertyGetNode getModuleBlockName = PropertyGetNode.createGetHidden(ModuleBlockNode.getHostDefinedSlotKey(), + this.context); + + Object bodyNode = this.body.getValue(specifier); + Object sourceText = getSourceCode.getValue(specifier); + Object moduleBlockName = getModuleBlockName.getValue(specifier); + + Object executedBody = ((JavaScriptNode) bodyNode).execute(frame); + + Source source = Source.newBuilder(JavaScriptLanguage.ID, sourceText.toString(), (String) moduleBlockName).build(); + + return hostImportModuleDynamically(referencingScriptOrModule, specifier, source); + } + try { specifierString = toStringNode.executeString(specifier); } catch (Throwable ex) { @@ -145,6 +177,14 @@ private DynamicObject hostImportModuleDynamically(Object referencingScriptOrModu } } + private DynamicObject hostImportModuleDynamically(Object referencingScriptOrModule, Object specifier, Source source) { + JSRealm realm = context.getRealm(); + + PromiseCapabilityRecord promiseCapability = newPromiseCapability(); + context.promiseEnqueueJob(realm, createImportModuleDynamicallyJob((ScriptOrModule) referencingScriptOrModule, (DynamicObject) specifier, source, promiseCapability)); + return promiseCapability.getPromise(); + } + private PromiseCapabilityRecord newPromiseCapability() { if (newPromiseCapabilityNode == null) { CompilerDirectives.transferToInterpreterAndInvalidate(); @@ -185,24 +225,37 @@ public DynamicObject createImportModuleDynamicallyJob(ScriptOrModule referencing if (context.isOptionTopLevelAwait()) { Triple request = new Triple<>(referencingScriptOrModule, specifier, promiseCapability); PromiseCapabilityRecord startModuleLoadCapability = newPromiseCapability(); - PromiseReactionRecord startModuleLoad = PromiseReactionRecord.create(startModuleLoadCapability, createImportModuleDynamicallyHandler(), true); + PromiseReactionRecord startModuleLoad = PromiseReactionRecord.create(startModuleLoadCapability, createImportModuleDynamicallyHandler(RootType.TopLevelAwait), true); return promiseReactionJobNode.execute(startModuleLoad, request); } else { Pair request = new Pair<>(referencingScriptOrModule, specifier); - return promiseReactionJobNode.execute(PromiseReactionRecord.create(promiseCapability, createImportModuleDynamicallyHandler(), true), request); + return promiseReactionJobNode.execute(PromiseReactionRecord.create(promiseCapability, createImportModuleDynamicallyHandler(RootType.ImportModuleDynamically), true), request); } } + public DynamicObject createImportModuleDynamicallyJob(ScriptOrModule referencingScriptOrModule, DynamicObject specifier, Source source, PromiseCapabilityRecord promiseCapability) { + Triple request = new Triple<>(referencingScriptOrModule, specifier, source); + + return promiseReactionJobNode.execute(PromiseReactionRecord.create(promiseCapability, createImportModuleDynamicallyHandler(RootType.ModuleBlock), true), request); + } + /** * Returns a handler function to be used together with a PromiseReactionJob in order to perform * the steps of both HostImportModuleDynamically and FinishDynamicImport. */ - private DynamicObject createImportModuleDynamicallyHandler() { - JSFunctionData functionData = context.getOrCreateBuiltinFunctionData(JSContext.BuiltinFunctionKey.ImportModuleDynamically, (c) -> createImportModuleDynamicallyHandlerImpl(c)); + private DynamicObject createImportModuleDynamicallyHandler(RootType root) { + JSFunctionData functionData = context.getOrCreateBuiltinFunctionData(JSContext.BuiltinFunctionKey.ImportModuleDynamically, (c) -> createImportModuleDynamicallyHandlerImpl(c, root)); return JSFunction.create(context.getRealm(), functionData); } - private static JSFunctionData createImportModuleDynamicallyHandlerImpl(JSContext context) { + private static enum RootType { + ImportModuleDynamically, + TopLevelAwait, + ModuleBlock; + } + + private static JSFunctionData createImportModuleDynamicallyHandlerImpl(JSContext context, RootType type) { + class ImportModuleDynamicallyRootNode extends JavaScriptRootNode { @Child protected JavaScriptNode argumentNode = AccessIndexedArgumentNode.create(0); @@ -283,7 +336,61 @@ private boolean shouldCatch(Throwable exception) { } } - JavaScriptRootNode root = context.isOptionTopLevelAwait() ? new TopLevelAwaitImportModuleDynamicallyRootNode() : new ImportModuleDynamicallyRootNode(); + class ModuleBlockRootNode extends JavaScriptRootNode { + + @Child protected JavaScriptNode argumentNode = AccessIndexedArgumentNode.create(0); + + @Override + public Object execute(VirtualFrame frame) { + assert argumentNode.execute(frame) instanceof Triple; + Triple request = (Triple) argumentNode.execute(frame); + + assert request.getFirst() instanceof ScriptOrModule; + ScriptOrModule referencingScriptOrModule = (ScriptOrModule) request.getFirst(); + + assert request.getSecond() instanceof DynamicObject; + DynamicObject moduleBlock = (DynamicObject) request.getSecond(); + + assert request.getThird() instanceof Source; + Source source = (Source) request.getThird(); + + JSModuleRecord test = context.getEvaluator().hostResolveImportedModule(context, referencingScriptOrModule, moduleBlock, source); + + return finishDynamicImport(context.getRealm(), test, referencingScriptOrModule, moduleBlock); + } + + protected Object finishDynamicImport(JSRealm realm, JSModuleRecord moduleRecord, ScriptOrModule referencingScriptOrModule, DynamicObject specifier) { + context.getEvaluator().moduleInstantiation(realm, moduleRecord); + context.getEvaluator().moduleEvaluation(realm, moduleRecord); + if (moduleRecord.getEvaluationError() != null) { + throw JSRuntime.rethrow(moduleRecord.getEvaluationError()); + } + // Note: PromiseReactionJob performs the promise rejection and resolution. + // Probably unwanted in module blocks since we do not need to get the module block + // via specifier + assert moduleRecord == context.getEvaluator().hostResolveImportedModuleBlock(context, referencingScriptOrModule, moduleRecord, specifier); + // Evaluate has already been invoked on moduleRecord and successfully completed. + assert moduleRecord.isEvaluated(); + return context.getEvaluator().getModuleNamespace(moduleRecord); + } + + } + + JavaScriptRootNode root; + switch (type) { + case TopLevelAwait: + root = new TopLevelAwaitImportModuleDynamicallyRootNode(); + break; + case ImportModuleDynamically: + root = new ImportModuleDynamicallyRootNode(); + break; + case ModuleBlock: + root = new ModuleBlockRootNode(); + break; + default: + root = null; + } + CallTarget callTarget = Truffle.getRuntime().createCallTarget(root); return JSFunctionData.createCallOnly(context, callTarget, 0, ""); } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java index 87e96ebe537..d1b7739f18f 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/Evaluator.java @@ -47,6 +47,7 @@ import com.oracle.truffle.api.source.Source; import com.oracle.truffle.js.nodes.JavaScriptNode; import com.oracle.truffle.js.nodes.ScriptNode; +import com.oracle.truffle.js.nodes.module.ModuleBlockNode; import com.oracle.truffle.js.runtime.objects.ExportResolution; import com.oracle.truffle.js.runtime.objects.JSModuleLoader; import com.oracle.truffle.js.runtime.objects.JSModuleRecord; @@ -65,6 +66,11 @@ public interface Evaluator { */ ScriptNode parseEval(JSContext context, Node lastNode, Source code); + /** + * Parse module block code using the global execution context + */ + JavaScriptNode parseModuleBlock(JSContext context, Source source); + /** * Parse direct eval code using the local execution context. * @@ -85,6 +91,10 @@ public interface Evaluator { JSModuleRecord hostResolveImportedModule(JSContext context, ScriptOrModule referencingScriptOrModule, String specifier); + JSModuleRecord hostResolveImportedModule(JSContext context, ScriptOrModule referencingScriptOrModule, DynamicObject moduleBlock, Source source); + + JSModuleRecord hostResolveImportedModuleBlock(JSContext context, ScriptOrModule referencingScriptOrModule, JSModuleRecord moduleRecord, DynamicObject specifier); + void moduleInstantiation(JSRealm realm, JSModuleRecord moduleRecord); Object moduleEvaluation(JSRealm realm, JSModuleRecord moduleRecord); diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContext.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContext.java index 7259f23e602..ec263cc345d 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContext.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContext.java @@ -90,6 +90,7 @@ import com.oracle.truffle.js.runtime.builtins.JSFunctionFactory; import com.oracle.truffle.js.runtime.builtins.JSGlobal; import com.oracle.truffle.js.runtime.builtins.JSMap; +import com.oracle.truffle.js.runtime.builtins.JSModuleBlock; import com.oracle.truffle.js.runtime.builtins.JSModuleNamespace; import com.oracle.truffle.js.runtime.builtins.JSNumber; import com.oracle.truffle.js.runtime.builtins.JSObjectFactory; @@ -307,6 +308,7 @@ public enum BuiltinFunctionKey { WebAssemblyGlobalGetValue, WebAssemblyGlobalSetValue, WebAssemblySourceInstantiation, + ModuleBlock, } @CompilationFinal(dimensions = 1) private final JSFunctionData[] builtinFunctionData; @@ -417,6 +419,8 @@ public enum BuiltinFunctionKey { private final JSObjectFactory webAssemblyTableFactory; private final JSObjectFactory webAssemblyGlobalFactory; + private final JSObjectFactory moduleBlockFactory; + private final int factoryCount; @CompilationFinal private Locale locale; @@ -575,6 +579,8 @@ protected JSContext(Evaluator evaluator, JSContextOptions contextOptions, JavaSc this.webAssemblyTableFactory = builder.create(JSWebAssemblyTable.INSTANCE); this.webAssemblyGlobalFactory = builder.create(JSWebAssemblyGlobal.INSTANCE); + this.moduleBlockFactory = builder.create(JSModuleBlock.INSTANCE); + this.factoryCount = builder.finish(); this.argumentsPropertyProxy = new JSFunction.ArgumentsProxyProperty(this); @@ -1025,6 +1031,10 @@ public JSObjectFactory getWebAssemblyGlobalFactory() { return webAssemblyGlobalFactory; } + public JSObjectFactory getModuleBlockFactory() { + return moduleBlockFactory; + } + private static final String REGEX_OPTION_U180E_WHITESPACE = "U180EWhitespace"; private static final String REGEX_OPTION_REGRESSION_TEST_MODE = "RegressionTestMode"; private static final String REGEX_OPTION_DUMP_AUTOMATA = "DumpAutomata"; @@ -1734,4 +1744,8 @@ public boolean isOptionTopLevelAwait() { public boolean isWaitAsyncEnabled() { return getEcmaScriptVersion() >= JSConfig.ECMAScript2022; } + + public boolean isExperimentalModuleBlocks() { + return getContextOptions().isExperimentalModuleBlocks(); + } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java index ec9ade4fe87..14268a9c48a 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSContextOptions.java @@ -498,6 +498,15 @@ public Map apply(String value) { public static final OptionKey NEW_SET_METHODS = new OptionKey<>(false); @CompilationFinal private boolean newSetMethods; + public static final String MODULE_BLOCKS_NAME = JS_OPTION_PREFIX + "module-blocks"; + @Option(name = MODULE_BLOCKS_NAME, category = OptionCategory.USER, help = "Enable the use of module blocks.") public static final OptionKey MODULE_BLOCKS = new OptionKey<>(false); + @CompilationFinal private boolean moduleBlocks; + + public static final String EXPERIMENTAL_MODULE_BLOCK_SERIALIZATION_API = JS_OPTION_PREFIX + "experimental-module-block-serialization-api"; + @Option(name = EXPERIMENTAL_MODULE_BLOCK_SERIALIZATION_API, category = OptionCategory.EXPERT, help = "Enable serialize and deserialize api for module blocks.") public static final OptionKey EXPERIMENTAL_MODULE_BLOCKS = new OptionKey<>( + false); + @CompilationFinal private boolean moduleBlocksSerializationAPI; + public enum UnhandledRejectionsTrackingMode { NONE, WARN, @@ -613,6 +622,8 @@ private void cacheOptions() { this.webAssembly = readBooleanOption(WEBASSEMBLY); this.unhandledRejectionsMode = readUnhandledRejectionsMode(); this.newSetMethods = readBooleanOption(NEW_SET_METHODS); + this.moduleBlocks = readBooleanOption(MODULE_BLOCKS); + this.moduleBlocksSerializationAPI = readBooleanOption(EXPERIMENTAL_MODULE_BLOCKS); this.operatorOverloading = readBooleanOption(OPERATOR_OVERLOADING); this.propertyCacheLimit = readIntegerOption(PROPERTY_CACHE_LIMIT); @@ -984,6 +995,14 @@ public boolean isNewSetMethods() { return newSetMethods; } + public boolean isModuleBlocks() { + return moduleBlocks; + } + + public boolean isExperimentalModuleBlocks() { + return moduleBlocksSerializationAPI; + } + public boolean isOperatorOverloading() { return operatorOverloading; } @@ -1040,6 +1059,8 @@ public int hashCode() { hash = 53 * hash + (this.webAssembly ? 1 : 0); hash = 53 * hash + this.unhandledRejectionsMode.ordinal(); hash = 53 * hash + (this.newSetMethods ? 1 : 0); + hash = 53 * hash + (this.moduleBlocks ? 1 : 0); + hash = 53 * hash + (this.moduleBlocksSerializationAPI ? 1 : 0); hash = 53 * hash + (this.operatorOverloading ? 1 : 0); return hash; } @@ -1200,6 +1221,12 @@ public boolean equals(Object obj) { if (this.newSetMethods != other.newSetMethods) { return false; } + if (this.moduleBlocks != other.moduleBlocks) { + return false; + } + if (this.moduleBlocksSerializationAPI != other.moduleBlocksSerializationAPI) { + return false; + } if (this.operatorOverloading != other.operatorOverloading) { return false; } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java index 31bf8bb402f..5e4f60cefe3 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java @@ -121,6 +121,7 @@ import com.oracle.truffle.js.runtime.builtins.JSGlobal; import com.oracle.truffle.js.runtime.builtins.JSMap; import com.oracle.truffle.js.runtime.builtins.JSMath; +import com.oracle.truffle.js.runtime.builtins.JSModuleBlock; import com.oracle.truffle.js.runtime.builtins.JSNumber; import com.oracle.truffle.js.runtime.builtins.JSON; import com.oracle.truffle.js.runtime.builtins.JSObjectFactory; @@ -307,6 +308,9 @@ public class JSRealm { private final DynamicObject asyncGeneratorFunctionConstructor; private final DynamicObject asyncGeneratorFunctionPrototype; + private final DynamicObject moduleBlockConstructor; + private final DynamicObject moduleBlockPrototype; + private final DynamicObject throwerFunction; private final Accessor throwerAccessor; @@ -662,6 +666,15 @@ public JSRealm(JSContext context, TruffleLanguage.Env env) { this.finalizationRegistryPrototype = null; } + if (isModuleBlockAvailable()) { + ctor = JSModuleBlock.createConstructor(this); + this.moduleBlockConstructor = ctor.getFunctionObject(); + this.moduleBlockPrototype = ctor.getPrototype(); + } else { + this.moduleBlockConstructor = null; + this.moduleBlockPrototype = null; + } + boolean nashornCompat = context.isOptionNashornCompatibilityMode(); if (nashornCompat) { ctor = JSAdapter.createConstructor(this); @@ -1398,6 +1411,7 @@ public void setupGlobals() { putGlobalProperty(JSWeakRef.CLASS_NAME, getWeakRefConstructor()); putGlobalProperty(JSFinalizationRegistry.CLASS_NAME, getFinalizationRegistryConstructor()); } + if (context.getContextOptions().isGraalBuiltin()) { putGraalObject(); } @@ -1409,13 +1423,19 @@ public void setupGlobals() { JSObjectUtil.putDataProperty(context, webAssemblyObject, JSFunction.getName(webAssemblyModuleConstructor), webAssemblyModuleConstructor, JSAttributes.getDefaultNotEnumerable()); JSObjectUtil.putDataProperty(context, webAssemblyObject, JSFunction.getName(webAssemblyTableConstructor), webAssemblyTableConstructor, JSAttributes.getDefaultNotEnumerable()); } + if (context.getContextOptions().isOperatorOverloading()) { JSObjectUtil.putFunctionsFromContainer(this, global, OperatorsBuiltins.BUILTINS); } + if (isModuleBlockAvailable()) { + putGlobalProperty(JSModuleBlock.CLASS_NAME, getModuleBlockConstructor()); + } + if (context.getContextOptions().isProfileTime()) { System.out.println("SetupGlobals: " + (System.nanoTime() - time) / 1000000); } + } private void initGlobalNashornExtensions() { @@ -2453,4 +2473,15 @@ public DynamicObject getForeignIterablePrototype() { return foreignIterablePrototype; } + private boolean isModuleBlockAvailable() { + return getContext().getContextOptions().isModuleBlocks(); + } + + public final DynamicObject getModuleBlockConstructor() { + return moduleBlockConstructor; + } + + public final DynamicObject getModuleBlockPrototype() { + return moduleBlockPrototype; + } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSModuleBlock.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSModuleBlock.java new file mode 100644 index 00000000000..24f21ac981d --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSModuleBlock.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.runtime.builtins; + +import com.oracle.truffle.api.object.DynamicObject; +import com.oracle.truffle.js.builtins.MapPrototypeBuiltins; +import com.oracle.truffle.js.builtins.ModuleBlockPrototypeBuiltins; +import com.oracle.truffle.js.runtime.JSContext; +import com.oracle.truffle.js.runtime.JSRealm; +import com.oracle.truffle.js.runtime.objects.JSObjectUtil; + +public class JSModuleBlock extends JSNonProxy implements JSConstructorFactory.Default.WithSpecies, PrototypeSupplier { + + public static final JSModuleBlock INSTANCE = new JSModuleBlock(); + + public static final String CLASS_NAME = "ModuleBlock"; + public static final String PROTOTYPE_NAME = "ModuleBlock.prototype"; + + private JSModuleBlock() { + } + + public static DynamicObject create(JSContext context) { + + JSRealm realm = context.getRealm(); + JSObjectFactory factory = context.getModuleBlockFactory(); + DynamicObject obj = factory.initProto(new JSModuleBlockObject(factory.getShape(realm)), realm); + assert isJSModuleBlock(obj); + return context.trackAllocation(obj); + } + + @Override + public String getClassName() { + return CLASS_NAME; + } + + @Override + public String getClassName(DynamicObject object) { + return getClassName(); + } + + @Override + public DynamicObject createPrototype(JSRealm realm, DynamicObject constructor) { + DynamicObject prototype = JSObjectUtil.createOrdinaryPrototypeObject(realm); + + JSObjectUtil.putFunctionsFromContainer(realm, prototype, ModuleBlockPrototypeBuiltins.BUILTINS); + JSObjectUtil.putToStringTag(prototype, CLASS_NAME); + + return prototype; + } + + @Override + public DynamicObject getIntrinsicDefaultProto(JSRealm realm) { + return realm.getModuleBlockPrototype(); + } + + public static JSConstructor createConstructor(JSRealm realm) { + return INSTANCE.createConstructorAndPrototype(realm); + } + + public static boolean isJSModuleBlock(Object obj) { + return obj instanceof JSModuleBlockObject; + } + +} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSModuleBlockObject.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSModuleBlockObject.java new file mode 100644 index 00000000000..c9c20d0f72a --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSModuleBlockObject.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.oracle.truffle.js.runtime.builtins; + +import com.oracle.truffle.api.object.Shape; +import com.oracle.truffle.js.runtime.objects.JSNonProxyObject; + +public class JSModuleBlockObject extends JSNonProxyObject { + + protected JSModuleBlockObject(Shape shape) { + super(shape); + } +} diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java index 3352771566e..1ae8a9d6436 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/DefaultESModuleLoader.java @@ -41,6 +41,7 @@ package com.oracle.truffle.js.runtime.objects; import com.oracle.truffle.api.TruffleFile; +import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.js.lang.JavaScriptLanguage; import com.oracle.truffle.js.runtime.Errors; @@ -58,7 +59,7 @@ public class DefaultESModuleLoader implements JSModuleLoader { protected final JSRealm realm; - protected final Map moduleMap = new HashMap<>(); + protected final Map moduleMap = new HashMap<>(); public static DefaultESModuleLoader create(JSRealm realm) { return new DefaultESModuleLoader(realm); @@ -157,4 +158,35 @@ public JSModuleRecord loadModule(Source source) { } return moduleMap.computeIfAbsent(canonicalPath, (key) -> realm.getContext().getEvaluator().parseModule(realm.getContext(), source, this)); } + + @Override + public JSModuleRecord resolveImportedModuleBlock(JSModuleRecord moduleBlock, DynamicObject specifier) { + return loadModuleBlock(moduleBlock, specifier); + } + + protected JSModuleRecord loadModuleBlock(JSModuleRecord moduleBlock, DynamicObject specifier) { + JSModuleRecord existingModule = moduleMap.get(specifier); + + if (existingModule != null) { + return existingModule; + } + + moduleMap.put(specifier, moduleBlock); + + return moduleBlock; + } + + @Override + public JSModuleRecord resolveImportedModuleBlock(Source source, DynamicObject specifier) { + return loadModuleBlock(source, specifier); + } + + protected JSModuleRecord loadModuleBlock(Source source, DynamicObject specifier) { + JSModuleRecord existingModule = moduleMap.get(specifier); + if (existingModule != null) { + return existingModule; + } + + return moduleMap.computeIfAbsent(specifier, (key) -> realm.getContext().getEvaluator().parseModule(realm.getContext(), source, this)); + } } diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleLoader.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleLoader.java index f4539281d02..b8649a9be3d 100644 --- a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleLoader.java +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/objects/JSModuleLoader.java @@ -40,10 +40,15 @@ */ package com.oracle.truffle.js.runtime.objects; +import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.source.Source; public interface JSModuleLoader { JSModuleRecord resolveImportedModule(ScriptOrModule referencingModule, String specifier); JSModuleRecord loadModule(Source moduleSource); + + JSModuleRecord resolveImportedModuleBlock(Source source, DynamicObject specifier); + + JSModuleRecord resolveImportedModuleBlock(JSModuleRecord moduleBlock, DynamicObject specifier); } diff --git a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java index dc7a0cb9e6a..8b50a455a92 100644 --- a/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java +++ b/graal-nodejs/mx.graal-nodejs/com.oracle.truffle.trufflenode/src/com/oracle/truffle/trufflenode/GraalJSAccess.java @@ -3784,6 +3784,16 @@ public JSModuleRecord resolveImportedModule(ScriptOrModule referrer, String spec public JSModuleRecord loadModule(Source moduleSource) { throw new UnsupportedOperationException(); } + + @Override + public JSModuleRecord resolveImportedModuleBlock(JSModuleRecord moduleBlock, DynamicObject specifier) { + return moduleBlock; + } + + @Override + public JSModuleRecord resolveImportedModuleBlock(Source source, DynamicObject specifier) { + throw new UnsupportedOperationException(); + } } /** diff --git a/graal-nodejs/test/graal/unit/workerModuleBlock.js b/graal-nodejs/test/graal/unit/workerModuleBlock.js new file mode 100644 index 00000000000..d0a8d1b84b7 --- /dev/null +++ b/graal-nodejs/test/graal/unit/workerModuleBlock.js @@ -0,0 +1,18 @@ +const assert = require('assert'); + +const { + Worker, + isMainThread +} = require('worker_threads'); + +var worker = new Worker('java.lang.Thread.sleep(1000000)', {eval: true}); + worker.on('online', function () { + setTimeout(function () { + worker.terminate(); + }, 1000); + }); + +var moduleBlock = module { export var test = 5;}; + +worker.postMessage(moduleBlock.toString()); +worker.postMessage(ModuleBlock.prototype.serialize(moduleBlock)); \ No newline at end of file