From 8088017cd58bb979b94137197756360beca4428f Mon Sep 17 00:00:00 2001 From: KamikazeSquirrel <64982603+KamikazeSquirrel@users.noreply.github.com> Date: Wed, 30 Jun 2021 09:00:10 +0200 Subject: [PATCH 1/8] module block proposal implementation --- .../src/com/oracle/js/parser/Parser.java | 71 ++++++++--- .../com/oracle/js/parser/ir/FunctionNode.java | 7 ++ .../truffle/js/parser/GraalJSEvaluator.java | 22 ++++ .../truffle/js/parser/GraalJSTranslator.java | 12 +- .../js/parser/JavaScriptTranslator.java | 8 ++ .../truffle/js/test/interop/ESModuleTest.java | 116 ++++++++++++++++++ .../resources/moduleblock/moduleBlockAsync.js | 65 ++++++++++ .../moduleblock/moduleBlockComparison.js | 48 ++++++++ .../moduleBlockFunctionExportTestMimic.js | 70 +++++++++++ .../moduleblock/moduleBlockPrototype.js | 89 ++++++++++++++ .../js/builtins/ConstructorBuiltins.java | 3 + .../truffle/js/builtins/DebugBuiltins.java | 10 ++ .../truffle/js/builtins/GlobalBuiltins.java | 58 +++++++++ .../ModuleBlockPrototypeBuiltins.java | 95 ++++++++++++++ .../com/oracle/truffle/js/nodes/JSGuards.java | 5 + .../oracle/truffle/js/nodes/NodeFactory.java | 5 + .../js/nodes/module/ModuleBlockNode.java | 93 ++++++++++++++ .../js/nodes/promise/ImportCallNode.java | 110 ++++++++++++++++- .../oracle/truffle/js/runtime/Evaluator.java | 10 ++ .../oracle/truffle/js/runtime/JSContext.java | 10 ++ .../oracle/truffle/js/runtime/JSRealm.java | 31 +++++ .../js/runtime/builtins/JSModuleBlock.java | 66 ++++++++++ .../runtime/builtins/JSModuleBlockObject.java | 11 ++ .../objects/DefaultESModuleLoader.java | 34 ++++- .../js/runtime/objects/JSModuleLoader.java | 5 + 25 files changed, 1029 insertions(+), 25 deletions(-) create mode 100644 graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockAsync.js create mode 100644 graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockComparison.js create mode 100644 graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockFunctionExportTestMimic.js create mode 100644 graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockPrototype.js create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ModuleBlockPrototypeBuiltins.java create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ModuleBlockNode.java create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSModuleBlock.java create mode 100644 graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSModuleBlockObject.java diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java index 5cde6e3a640..24f3b1d5fa4 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 @@ -276,6 +276,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 +452,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 +3604,7 @@ private void debuggerStatement() { * RegularExpressionLiteral * TemplateLiteral * CoverParenthesizedExpressionAndArrowParameterList + * ModuleBlockExpression * * CoverParenthesizedExpressionAndArrowParameterList : * ( Expression ) @@ -3625,10 +3628,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 + "T" + start, true); + } + final IdentNode ident = identifierReference(yield, await); + if (ident == null) { break; } + return detectSpecialProperty(ident); case NON_OCTAL_DECIMAL: if (isStrictMode) { @@ -6298,20 +6314,34 @@ 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 ParserContextFunctionNode script = createParserContextFunctionNode( - ident, - functionToken, - FunctionNode.IS_MODULE, - functionLine, - Collections. emptyList(), 0, moduleScope); + final ParserContextFunctionNode script; + + final IdentNode ident = moduleBlock ? new IdentNode(functionToken, finish, moduleName) : null; + + if (moduleBlock) { + script = createParserContextFunctionNode( + ident, + functionToken, + FunctionNode.IS_MODULE_BLOCK, + functionLine, + Collections. emptyList(), 0, moduleScope); + + } else { + script = createParserContextFunctionNode( + ident, + functionToken, + FunctionNode.IS_MODULE, + functionLine, + Collections. emptyList(), 0, moduleScope); + + } script.setInternalName(moduleName); lc.push(script); @@ -6320,7 +6350,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 +6359,12 @@ private FunctionNode module(final String moduleName) { addFunctionDeclarations(script); } finally { - functionDeclarations = null; + if (moduleBlock) { + functionDeclarations = Collections.emptyList(); + } else { + functionDeclarations = null; + } + restoreBlock(body); lc.pop(script); } @@ -6338,7 +6373,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 +6400,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..70f386c0042 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,14 @@ public ScriptNode parseEval(JSContext context, Node lastNode, Source source) { return parseEval(context, lastNode, source, false, null); } + // TODO + @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 +379,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 { + 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); + +[five]; \ 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/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..5b228525d23 --- /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,48 @@ +(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."); +})(); + +// 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."); +})(); + +*/ \ 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/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..8da65402a27 --- /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) 2020, 2020, 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]; \ 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/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..e5714e5bd9e --- /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) 2020, 2020, 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 Object) { + sq = squareTest.then(function(value) { return module.square(value.t); }); +} else { + sq = 0; +} + +if (Object.getPrototypeOf(moduleBlock) === Object.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]; \ No newline at end of file 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..ff8d6ea795e 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(1), // 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..fbb9b13cc1b 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. */ @@ -173,6 +179,10 @@ public enum Global implements BuiltinEnum { decodeURIComponent(1), eval(1), + // ModuleBlock methods + serialize(1), + deserialize(1), + // Annex B escape(1), unescape(1); @@ -215,6 +225,10 @@ 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 serialize: + return JSGlobalSerializeNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context)); + case deserialize: + return JSGlobalDeserializeNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context)); case escape: return JSGlobalUnEscapeNodeGen.create(context, builtin, false, args().fixedArgs(1).createArgumentNodes(context)); case unescape: @@ -1284,6 +1298,50 @@ public boolean isCallerSensitive() { } } + /** + * Implementation of Module Block serialize-method + */ + public abstract static class JSGlobalSerializeNode extends JSBuiltinNode { + + protected JSGlobalSerializeNode(JSContext context, JSBuiltin builtin) { + super(context, builtin); + } + + protected byte[] serialize(Object value) { + if (DynamicObjectLibrary.getUncached().containsKey((DynamicObject) value, (Object) ModuleBlockNode.getModuleBodyKey())) { + PropertyGetNode getSourceCode = PropertyGetNode.createGetHidden(ModuleBlockNode.getModuleSourceKey(), getContext()); + + Object sourceCode = getSourceCode.getValue(value); + + return ("module {" + sourceCode.toString() + "}").getBytes(); + } + + // TODO Errors.createTypeError("Not a ModuleBlock"); + + return null; + } + } + + /** + * Implementation of Module Block deserialize-method + */ + public abstract static class JSGlobalDeserializeNode extends JSBuiltinNode { + + protected JSGlobalDeserializeNode(JSContext context, JSBuiltin builtin) { + super(context, builtin); + } + + protected JavaScriptNode deserialize(Object value) { + String sourceCode = new String((byte[]) value, StandardCharsets.UTF_8); + + // get from sourcecode string to module block via parsing and then translating + + Source source = Source.newBuilder(JavaScriptLanguage.ID, sourceCode, "moduleBlock").build(); + + return getContext().getEvaluator().parseModuleBlock(getContext(), source); + } + } + /** * Implementation of ECMAScript 5.1 B.2.1 escape() method and of ECMAScript 5.1 B.2.2 unescape() * method. 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..5bb956dccf9 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ModuleBlockPrototypeBuiltins.java @@ -0,0 +1,95 @@ +package com.oracle.truffle.js.builtins; + +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.js.builtins.ArrayIteratorPrototypeBuiltinsFactory.ArrayIteratorNextNodeGen; +import com.oracle.truffle.js.builtins.ArrayPrototypeBuiltinsFactory.JSArrayToStringNodeGen; +import com.oracle.truffle.js.builtins.ModuleBlockPrototypeBuiltinsFactory.JSModuleBlockToStringNodeGen; +import com.oracle.truffle.js.builtins.DatePrototypeBuiltins.JSDateOperation; +import com.oracle.truffle.js.nodes.access.HasHiddenKeyCacheNode; +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.builtins.BuiltinEnum; +import com.oracle.truffle.js.runtime.builtins.JSDate; +import com.oracle.truffle.js.runtime.builtins.JSModuleBlock; +import com.oracle.truffle.js.runtime.util.WeakMap; + +/** + * 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); + + 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)); + } + return null; + } + + public abstract static class JSModuleBlockToStringNode extends JSBuiltinNode { + + JSContext context_; + DynamicObject prototype; + + public JSModuleBlockToStringNode(JSContext context, JSBuiltin builtin) { + super(context, builtin); + + prototype = context.getRealm().getModuleBlockPrototype(); + } + + // TODO + @Specialization(guards = "isJSOrdinaryObject(thisModuleBlock)") + protected String doOperation(Object thisModuleBlock) { + // TODO Type check, then check for hidden property body and return hidden property + // sourceText + + if (DynamicObjectLibrary.getUncached().containsKey((DynamicObject) thisModuleBlock, (Object) ModuleBlockNode.getModuleBodyKey())) { + PropertyGetNode getSourceCode = PropertyGetNode.createGetHidden(ModuleBlockNode.getModuleSourceKey(), this.getContext()); + + Object sourceCode = getSourceCode.getValue(thisModuleBlock); + + return "module {" + sourceCode.toString() + " }"; + } else if (thisModuleBlock.equals(this.getContext().getRealm().getModuleBlockPrototype())) { + return JSModuleBlock.PROTOTYPE_NAME; + } + + notJSModuleBlock(thisModuleBlock); + + return ""; + } + + @Specialization(guards = "!isJSOrdinaryObject(thisModuleBlock)") + protected static boolean notJSModuleBlock(Object thisModuleBlock) { + throw Errors.createTypeError("Not a module block"); + } + + } +} \ 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..d32233749fd --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/nodes/module/ModuleBlockNode.java @@ -0,0 +1,93 @@ +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"; + public static final String CLASS_NAME = "ModuleBlock"; + public static final String PROTOTYPE_NAME = "ModuleBlock.prototype"; + + 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..9e4d2c81606 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,10 @@ 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.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; @@ -74,6 +77,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 +95,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 +118,25 @@ public Object execute(VirtualFrame frame) { Object referencingScriptOrModule = getActiveScriptOrModule(frame); Object specifier = argRefNode.execute(frame); String specifierString; + + if (specifier instanceof DynamicObject && DynamicObjectLibrary.getUncached().containsKey((DynamicObject) specifier, (Object) 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 +173,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 +221,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.TLA), 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.IMD), 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.MB), 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 { + IMD, + TLA, + MB; + } + + private static JSFunctionData createImportModuleDynamicallyHandlerImpl(JSContext context, RootType type) { + class ImportModuleDynamicallyRootNode extends JavaScriptRootNode { @Child protected JavaScriptNode argumentNode = AccessIndexedArgumentNode.create(0); @@ -283,7 +332,56 @@ 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) { + @SuppressWarnings("unchecked") + Triple request = (Triple) argumentNode.execute(frame); + + ScriptOrModule referencingScriptOrModule = request.getFirst(); + DynamicObject moduleBlock = request.getSecond(); + 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 TLA: + root = new TopLevelAwaitImportModuleDynamicallyRootNode(); + break; + case IMD: + root = new ImportModuleDynamicallyRootNode(); + break; + case MB: + 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..a98eca5b8dd 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"; 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..0ce761ff9eb 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); @@ -1416,6 +1429,10 @@ public void setupGlobals() { if (context.getContextOptions().isProfileTime()) { System.out.println("SetupGlobals: " + (System.nanoTime() - time) / 1000000); } + + if (isModuleBlockAvailable()) { + putGlobalProperty(JSModuleBlock.CLASS_NAME, getModuleBlockConstructor()); + } } private void initGlobalNashornExtensions() { @@ -2453,4 +2470,18 @@ public DynamicObject getForeignIterablePrototype() { return foreignIterablePrototype; } + // TODO + private boolean isModuleBlockAvailable() { + return true; + // return truffleLanguageEnv.isPolyglotBindingsAccessAllowed() && + // truffleLanguageEnv.getInternalLanguages().get("moduleBlock") != null; + } + + 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..598b6b6c976 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSModuleBlock.java @@ -0,0 +1,66 @@ +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) { + JSContext ctx = realm.getContext(); + 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); + } + + // TODO + public static boolean isJSModuleBlock(Object obj) { + + return true; + // 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..5860a69efb1 --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/builtins/JSModuleBlockObject.java @@ -0,0 +1,11 @@ +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); } From 025617a692f5e0674c1ec0556d75136d3c4c3fcc Mon Sep 17 00:00:00 2001 From: KamikazeSquirrel <64982603+KamikazeSquirrel@users.noreply.github.com> Date: Fri, 9 Jul 2021 08:20:18 +0200 Subject: [PATCH 2/8] added performance testing --- .../truffle/js/test/interop/ESModuleTest.java | 238 ++++++++++++++++++ .../moduleblock/benchmark/kMeansModule.js | 137 ++++++++++ .../benchmark/kMeansModuleBlock.js | 148 +++++++++++ .../benchmark/kMeansModuleImport.js | 45 ++++ .../benchmark/kMeansModuleModuleBlock.js | 148 +++++++++++ .../kMeansModuleModuleBlockImport.js | 44 ++++ .../moduleblock/benchmark/kMeansRegular.js | 140 +++++++++++ .../moduleblock/benchmark/toy/regular.js | 46 ++++ .../benchmark/toy/regularModuleBlock.js | 48 ++++ .../moduleblock/moduleBlockComparison.js | 41 +++ .../moduleblock/moduleBlockPrototype.js | 4 +- .../truffle/js/builtins/GlobalBuiltins.java | 6 +- .../oracle/truffle/js/runtime/JSRealm.java | 11 +- .../js/runtime/builtins/JSModuleBlock.java | 6 +- 14 files changed, 1049 insertions(+), 13 deletions(-) create mode 100644 graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModule.js create mode 100644 graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModuleBlock.js create mode 100644 graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModuleImport.js create mode 100644 graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModuleModuleBlock.js create mode 100644 graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModuleModuleBlockImport.js create mode 100644 graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansRegular.js create mode 100644 graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/toy/regular.js create mode 100644 graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/toy/regularModuleBlock.js diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ESModuleTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ESModuleTest.java index dc6cf401d09..bb28ffa98e2 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ESModuleTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ESModuleTest.java @@ -76,6 +76,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.LongStream; /** * Various tests for EcmaScript 6 module loading via {@link Source}. @@ -327,6 +328,243 @@ public void testModuleBlockComparison() throws IOException { } } + /** + * Benchmarktest for overhead, is kept running 1000 times each for comparison: 1. Regular file + * without imports and exports 2. Regular file with module import 3. Regular file without + * imports and exports but module block encapsulation 4. regular file with module import + * containing a module block encapsulation + */ + @Test + public void testModuleBlockBenchmark() throws IOException { + File[] allFilesArray = null; + + TestOutput out = new TestOutput(); + + long[] durations = new long[50]; + long startTime, endTime; + long timeConversion = 10; + + System.out.println("Benchmark for module blocks with k-means algorithm: "); + + try (Context context = JSTest.newContextBuilder().allowHostAccess(HostAccess.ALL).allowIO(true).err(out).out(out).option( + JSContextOptions.CONSOLE_NAME, "true").option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").build()) { + allFilesArray = prepareTestFileAndModules("resources/moduleBlock/benchmark/kMeansRegular.js"); + + Source mainSource = Source.newBuilder(ID, allFilesArray[0]).mimeType("application/javascript+module").build(); + + // initial eval + context.eval(mainSource); + + // warmup + for (int i = 0; i < 20; i++) { + context.parse(mainSource); + context.eval(mainSource); + } + + // benchmark + for (int i = 0; i < durations.length; i++) { + startTime = System.nanoTime(); + + context.parse(mainSource); + context.eval(mainSource); + + endTime = System.nanoTime(); + + durations[i] = (endTime - startTime) / timeConversion; + } + + System.out.println("Regular kMeans execution: " + LongStream.of(durations).summaryStatistics()); + LongStream.of(durations).forEach(System.out::println); + } finally { + deleteFiles(allFilesArray); + } + + out = new TestOutput(); + + try (Context context = JSTest.newContextBuilder().allowHostAccess(HostAccess.ALL).allowIO(true).err(out).out(out).option( + JSContextOptions.CONSOLE_NAME, "true").option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").build()) { + allFilesArray = prepareTestFileAndModules("resources/moduleBlock/benchmark/kMeansModuleBlock.js"); + + Source mainSource = Source.newBuilder(ID, allFilesArray[0]).mimeType("application/javascript+module").build(); + + // initial eval + context.eval(mainSource); + + // warmup + for (int i = 0; i < 20; i++) { + context.parse(mainSource); + context.eval(mainSource); + } + + // benchmark + for (int i = 0; i < durations.length; i++) { + startTime = System.nanoTime(); + + context.parse(mainSource); + context.eval(mainSource); + + endTime = System.nanoTime(); + + durations[i] = (endTime - startTime) / timeConversion; + } + + System.out.println("ModuleBlock kMeans execution: " + LongStream.of(durations).summaryStatistics()); + LongStream.of(durations).forEach(System.out::println); + + } finally { + deleteFiles(allFilesArray); + } + + out = new TestOutput(); + + try (Context context = JSTest.newContextBuilder().allowHostAccess(HostAccess.ALL).allowIO(true).err(out).out(out).option( + JSContextOptions.CONSOLE_NAME, "true").option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").build()) { + allFilesArray = prepareTestFileAndModules("resources/moduleBlock/benchmark/kMeansModuleImport.js", + "resources/moduleBlock/benchmark/kMeansModule.js"); + + Source mainSource = Source.newBuilder(ID, allFilesArray[0]).mimeType("application/javascript+module").build(); + + // initial eval + context.eval(mainSource); + + // warmup + for (int i = 0; i < 20; i++) { + context.parse(mainSource); + context.eval(mainSource); + } + + // benchmark + for (int i = 0; i < durations.length; i++) { + startTime = System.nanoTime(); + + context.parse(mainSource); + context.eval(mainSource); + + endTime = System.nanoTime(); + + durations[i] = (endTime - startTime) / timeConversion; + } + + System.out.println("Module kMeans execution: " + LongStream.of(durations).summaryStatistics()); + LongStream.of(durations).forEach(System.out::println); + + } finally { + deleteFiles(allFilesArray); + } + + out = new TestOutput(); + + try (Context context = JSTest.newContextBuilder().allowHostAccess(HostAccess.ALL).allowIO(true).err(out).out(out).option( + JSContextOptions.CONSOLE_NAME, "true").option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").build()) { + allFilesArray = prepareTestFileAndModules("resources/moduleBlock/benchmark/kMeansModuleModuleBlockImport.js", + "resources/moduleBlock/benchmark/kMeansModuleModuleBlock.js"); + + Source mainSource = Source.newBuilder(ID, allFilesArray[0]).mimeType("application/javascript+module").build(); + + // initial eval + context.eval(mainSource); + + // warmup + for (int i = 0; i < 20; i++) { + context.parse(mainSource); + context.eval(mainSource); + } + + // benchmark + for (int i = 0; i < durations.length; i++) { + startTime = System.nanoTime(); + + context.parse(mainSource); + context.eval(mainSource); + + endTime = System.nanoTime(); + + durations[i] = (endTime - startTime) / timeConversion; + } + + System.out.println("Module ModuleBlock kMeans execution: " + LongStream.of(durations).summaryStatistics()); + LongStream.of(durations).forEach(System.out::println); + + } finally { + deleteFiles(allFilesArray); + } + + System.out.println("Benchmark for module blocks with toy function returning 5:"); + + out = new TestOutput(); + + try (Context context = JSTest.newContextBuilder().allowHostAccess(HostAccess.ALL).allowIO(true).err(out).out(out).option( + JSContextOptions.CONSOLE_NAME, "true").option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").build()) { + allFilesArray = prepareTestFileAndModules("resources/moduleBlock/benchmark/toy/regular.js"); + + Source mainSource = Source.newBuilder(ID, allFilesArray[0]).mimeType("application/javascript+module").build(); + + // initial eval + context.eval(mainSource); + + // warmup + for (int i = 0; i < 20; i++) { + context.parse(mainSource); + context.eval(mainSource); + } + + // benchmark + for (int i = 0; i < durations.length; i++) { + startTime = System.nanoTime(); + + context.parse(mainSource); + context.eval(mainSource); + + endTime = System.nanoTime(); + + durations[i] = (endTime - startTime) / timeConversion; + } + + System.out.println("Regular toy function call: " + LongStream.of(durations).summaryStatistics()); + LongStream.of(durations).forEach(System.out::println); + + } finally { + deleteFiles(allFilesArray); + } + + out = new TestOutput(); + + try (Context context = JSTest.newContextBuilder().allowHostAccess(HostAccess.ALL).allowIO(true).err(out).out(out).option( + JSContextOptions.CONSOLE_NAME, "true").option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").build()) { + allFilesArray = prepareTestFileAndModules("resources/moduleBlock/benchmark/toy/regularModuleBlock.js"); + + Source mainSource = Source.newBuilder(ID, allFilesArray[0]).mimeType("application/javascript+module").build(); + + // initial eval + context.eval(mainSource); + + // warmup + for (int i = 0; i < 20; i++) { + context.parse(mainSource); + context.eval(mainSource); + } + + // benchmark + for (int i = 0; i < durations.length; i++) { + startTime = System.nanoTime(); + + context.parse(mainSource); + context.eval(mainSource); + + endTime = System.nanoTime(); + + durations[i] = (endTime - startTime) / timeConversion; + } + + System.out.println("Module block toy function call: " + LongStream.of(durations).summaryStatistics()); + LongStream.of(durations).forEach(System.out::println); + + } finally { + deleteFiles(allFilesArray); + } + + } + /** * Test basic function export. To be able to use the module API, MIME type * "application/javascript+module" is specified for the main file. 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..e34d92b4295 --- /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) 2020, 2020, 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(); + } +} \ 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/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..d093c8218ff --- /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) 2020, 2020, 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); +})(); \ 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/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..dc294fd6e9c --- /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) 2020, 2020, 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(); \ 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/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..98f3fe0f907 --- /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) 2020, 2020, 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); +}); \ 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/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..50da3ab873b --- /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) 2020, 2020, 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(); \ 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/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..01022d5b566 --- /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) 2020, 2020, 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(); \ 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/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..32d8cf87ad6 --- /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,46 @@ +/* + * Copyright (c) 2020, 2020, 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..1b15fd63d58 --- /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) 2020, 2020, 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); \ 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/moduleBlockComparison.js b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockComparison.js index 5b228525d23..fb360a474bc 100644 --- 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 @@ -1,3 +1,44 @@ +/* + * Copyright (c) 2020, 2020, 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; 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 index e5714e5bd9e..dd3ef6c1046 100644 --- 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 @@ -68,13 +68,13 @@ var sq; var dg; var st; -if (moduleBlock instanceof Object) { +if (moduleBlock instanceof ModuleBlock) { sq = squareTest.then(function(value) { return module.square(value.t); }); } else { sq = 0; } -if (Object.getPrototypeOf(moduleBlock) === Object.prototype) { +if (Object.getPrototypeOf(moduleBlock) === ModuleBlock.prototype) { dg = diagTest.then(value => module.diag(value.x, value.y)); } else { dg = 0; 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 fbb9b13cc1b..898400c2f2f 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 @@ -226,9 +226,11 @@ protected Object createNode(JSContext context, JSBuiltin builtin, boolean constr case eval: return JSGlobalIndirectEvalNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context)); case serialize: - return JSGlobalSerializeNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context)); + return JSGlobalSerializeNodeGen.create(context, builtin, + args().fixedArgs(1).createArgumentNodes(context)); case deserialize: - return JSGlobalDeserializeNodeGen.create(context, builtin, args().fixedArgs(1).createArgumentNodes(context)); + return JSGlobalDeserializeNodeGen.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/runtime/JSRealm.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/JSRealm.java index 0ce761ff9eb..c95da878607 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 @@ -666,7 +666,7 @@ public JSRealm(JSContext context, TruffleLanguage.Env env) { this.finalizationRegistryPrototype = null; } - if (!isModuleBlockAvailable()) { + if (isModuleBlockAvailable()) { ctor = JSModuleBlock.createConstructor(this); this.moduleBlockConstructor = ctor.getFunctionObject(); this.moduleBlockPrototype = ctor.getPrototype(); @@ -1411,6 +1411,7 @@ public void setupGlobals() { putGlobalProperty(JSWeakRef.CLASS_NAME, getWeakRefConstructor()); putGlobalProperty(JSFinalizationRegistry.CLASS_NAME, getFinalizationRegistryConstructor()); } + if (context.getContextOptions().isGraalBuiltin()) { putGraalObject(); } @@ -1422,17 +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); } - if (isModuleBlockAvailable()) { - putGlobalProperty(JSModuleBlock.CLASS_NAME, getModuleBlockConstructor()); - } } private void initGlobalNashornExtensions() { 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 index 598b6b6c976..e0061721b25 100644 --- 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 @@ -38,7 +38,6 @@ public String getClassName(DynamicObject object) { @Override public DynamicObject createPrototype(JSRealm realm, DynamicObject constructor) { - JSContext ctx = realm.getContext(); DynamicObject prototype = JSObjectUtil.createOrdinaryPrototypeObject(realm); JSObjectUtil.putFunctionsFromContainer(realm, prototype, ModuleBlockPrototypeBuiltins.BUILTINS); @@ -56,11 +55,8 @@ public static JSConstructor createConstructor(JSRealm realm) { return INSTANCE.createConstructorAndPrototype(realm); } - // TODO public static boolean isJSModuleBlock(Object obj) { - - return true; - // return obj instanceof JSModuleBlockObject; + return obj instanceof JSModuleBlockObject; } } From 48f99c3740f5c8c8b43aed68b1242b7d5e257e29 Mon Sep 17 00:00:00 2001 From: KamikazeSquirrel <64982603+KamikazeSquirrel@users.noreply.github.com> Date: Thu, 22 Jul 2021 21:14:24 +0200 Subject: [PATCH 3/8] first suggestion implementation --- .../src/com/oracle/js/parser/Parser.java | 37 +- .../truffle/js/parser/GraalJSEvaluator.java | 1 - .../js/parser/JavaScriptTranslator.java | 2 +- .../truffle/js/test/interop/ESModuleTest.java | 328 ++++-------------- .../moduleblock/benchmark/kMeansModule.js | 4 +- .../benchmark/kMeansModuleBlock.js | 4 +- .../benchmark/kMeansModuleImport.js | 4 +- .../benchmark/kMeansModuleModuleBlock.js | 4 +- .../kMeansModuleModuleBlockImport.js | 4 +- .../moduleblock/benchmark/kMeansRegular.js | 4 +- .../moduleblock/benchmark/toy/regular.js | 5 +- .../benchmark/toy/regularModuleBlock.js | 4 +- .../resources/moduleblock/moduleBlockAsync.js | 12 +- .../moduleblock/moduleBlockComparison.js | 12 +- .../moduleBlockFunctionExportTestMimic.js | 4 +- .../moduleblock/moduleBlockPrototype.js | 4 +- .../js/builtins/ConstructorBuiltins.java | 2 +- .../ModuleBlockPrototypeBuiltins.java | 53 ++- .../js/nodes/module/ModuleBlockNode.java | 42 ++- .../js/nodes/promise/ImportCallNode.java | 47 ++- .../truffle/js/runtime/JSContextOptions.java | 13 + .../oracle/truffle/js/runtime/JSRealm.java | 5 +- .../js/runtime/builtins/JSModuleBlock.java | 40 +++ .../runtime/builtins/JSModuleBlockObject.java | 40 +++ 24 files changed, 325 insertions(+), 350 deletions(-) diff --git a/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java b/graal-js/src/com.oracle.js.parser/src/com/oracle/js/parser/Parser.java index 24f3b1d5fa4..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; @@ -3632,11 +3634,11 @@ private Expression primaryExpression(boolean yield, boolean await) { final long identToken = token; String identString = (String) getValue(identToken); - if (identString.equals("module") && lookahead().equals(LBRACE)) { + if (identString.equals(MODULE) && lookahead().equals(LBRACE)) { nextOrEOL(); expect(LBRACE); - return module(source.getName() + "#L" + line + "T" + start, true); + return module(source.getName() + "#L" + line, true); } final IdentNode ident = identifierReference(yield, await); @@ -6321,27 +6323,16 @@ private FunctionNode module(final String moduleName, boolean moduleBlock) { final int functionLine = line; final Scope moduleScope = Scope.createModule(); - final ParserContextFunctionNode script; final IdentNode ident = moduleBlock ? new IdentNode(functionToken, finish, moduleName) : null; - if (moduleBlock) { - script = createParserContextFunctionNode( - ident, - functionToken, - FunctionNode.IS_MODULE_BLOCK, - functionLine, - Collections. emptyList(), 0, moduleScope); - - } else { - script = createParserContextFunctionNode( - ident, - functionToken, - FunctionNode.IS_MODULE, - functionLine, - Collections. emptyList(), 0, moduleScope); + final ParserContextFunctionNode script = createParserContextFunctionNode( + ident, + functionToken, + moduleBlock ? FunctionNode.IS_MODULE_BLOCK : FunctionNode.IS_MODULE, + functionLine, + Collections. emptyList(), 0, moduleScope); - } script.setInternalName(moduleName); lc.push(script); @@ -6359,11 +6350,9 @@ private FunctionNode module(final String moduleName, boolean moduleBlock) { addFunctionDeclarations(script); } finally { - if (moduleBlock) { - functionDeclarations = Collections.emptyList(); - } else { - functionDeclarations = null; - } + + // module blocks expect an empty list otherwise evaluating the code fails + functionDeclarations = moduleBlock ? Collections.emptyList() : null; restoreBlock(body); lc.pop(script); 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 70f386c0042..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 @@ -134,7 +134,6 @@ public ScriptNode parseEval(JSContext context, Node lastNode, Source source) { return parseEval(context, lastNode, source, false, null); } - // TODO @Override public JavaScriptNode parseModuleBlock(JSContext context, Source source) { NodeFactory nodeFactory = NodeFactory.getInstance(context); diff --git a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/JavaScriptTranslator.java b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/JavaScriptTranslator.java index 683e1fb5d7f..9e2014ec63e 100644 --- a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/JavaScriptTranslator.java +++ b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/JavaScriptTranslator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ESModuleTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ESModuleTest.java index bb28ffa98e2..c11f0339cdb 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ESModuleTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ESModuleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -215,18 +215,13 @@ private static void deleteFiles(File[] filesArray) { } } - /** - * Test basic module block features via mimicking the {@code} testFunctionExport() + - */ - @Test - public void testModuleBlockMimicFunctionExport() throws IOException { + private static void testModuleBlockMainMethod(String main, String module) throws IOException { File[] allFilesArray = null; TestOutput out = new TestOutput(); try (Context context = JSTest.newContextBuilder().allowHostAccess(HostAccess.ALL).allowIO(true).err(out).out(out).option( - JSContextOptions.CONSOLE_NAME, "true").option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").build()) { - allFilesArray = prepareTestFileAndModules("resources/moduleBlock/moduleBlockFunctionExportTestMimic.js", - "resources" + "/functionexportmodule.js"); + JSContextOptions.CONSOLE_NAME, "true").option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").option(JSContextOptions.MODULE_BLOCKS_NAME, "true").build()) { + allFilesArray = prepareTestFileAndModules(main, module); Source mainSource = Source.newBuilder(ID, allFilesArray[0]).mimeType("application/javascript+module").build(); @@ -239,39 +234,31 @@ public void testModuleBlockMimicFunctionExport() throws IOException { System.out.println("Square test: " + v.getArrayElement(0)); System.out.println("Diagonal test: " + v.getArrayElement(1)); System.out.println("Sqrt test: " + v.getArrayElement(2)); + + assertTrue(v.getArrayElement(0).toString().contains("121")); + assertTrue(v.getArrayElement(1).toString().contains("5")); + assertTrue(v.getArrayElement(2).toString().contains("11")); } finally { deleteFiles(allFilesArray); } } + /** + * Test basic module block features via mimicking the {@code} testFunctionExport() + + */ + @Test + public void testModuleBlockMimicFunctionExport() throws IOException { + testModuleBlockMainMethod("resources/moduleBlock/moduleBlockFunctionExportTestMimic.js", + "resources/functionexportmodule.js"); + } + /** * Test module block prototype behavior */ @Test public void testModuleBlockPrototype() throws IOException { - File[] allFilesArray = null; - - TestOutput out = new TestOutput(); - - try (Context context = JSTest.newContextBuilder().allowHostAccess(HostAccess.ALL).allowIO(true).err(out).out(out).option( - JSContextOptions.CONSOLE_NAME, "true").option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").build()) { - allFilesArray = prepareTestFileAndModules("resources/moduleBlock/moduleBlockPrototype.js", - "resources" + "/functionexportmodule.js"); - - Source mainSource = Source.newBuilder(ID, allFilesArray[0]).mimeType("application/javascript+module").build(); - - Value v = context.eval(mainSource); - - System.out.println(out); - - assertTrue(v.hasArrayElements()); - - System.out.println("Square test: " + v.getArrayElement(0)); - System.out.println("Diagonal test: " + v.getArrayElement(1)); - System.out.println("Sqrt test: " + v.getArrayElement(2)); - } finally { - deleteFiles(allFilesArray); - } + testModuleBlockMainMethod("resources/moduleBlock/moduleBlockPrototype.js", + "resources/functionexportmodule.js"); } /** @@ -279,28 +266,8 @@ public void testModuleBlockPrototype() throws IOException { */ @Test public void testModuleBlockAsync() throws IOException { - File[] allFilesArray = null; - - TestOutput out = new TestOutput(); - - try (Context context = JSTest.newContextBuilder().allowHostAccess(HostAccess.ALL).allowIO(true).err(out).out(out).option( - JSContextOptions.CONSOLE_NAME, "true").option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").build()) { - allFilesArray = prepareTestFileAndModules("resources/moduleBlock/moduleBlockAsync.js", - "resources" + "/functionexportmodule.js"); - - Source mainSource = Source.newBuilder(ID, allFilesArray[0]).mimeType("application/javascript+module").build(); - - Value v = context.eval(mainSource); - - System.out.println(out); - - assertTrue(v.hasArrayElements()); - - System.out.println("Async test: " + v.getArrayElement(0)); - - } finally { - deleteFiles(allFilesArray); - } + testModuleBlockMainMethod("resources/moduleBlock/moduleBlockAsync.js", + "resources/functionexportmodule.js"); } /** @@ -308,119 +275,34 @@ public void testModuleBlockAsync() throws IOException { */ @Test public void testModuleBlockComparison() throws IOException { - File[] allFilesArray = null; - - TestOutput out = new TestOutput(); - - try (Context context = JSTest.newContextBuilder().allowHostAccess(HostAccess.ALL).allowIO(true).err(out).out(out).option( - JSContextOptions.CONSOLE_NAME, "true").option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").build()) { - allFilesArray = prepareTestFileAndModules("resources/moduleBlock/moduleBlockComparison.js", - "resources" + "/functionexportmodule.js"); - - Source mainSource = Source.newBuilder(ID, allFilesArray[0]).mimeType("application/javascript+module").build(); - - Value v = context.eval(mainSource); - - System.out.println(out); - - } finally { - deleteFiles(allFilesArray); - } + testModuleBlockMainMethod("resources/moduleBlock/moduleBlockComparison.js", + "resources/functionexportmodule.js"); } /** - * Benchmarktest for overhead, is kept running 1000 times each for comparison: 1. Regular file - * without imports and exports 2. Regular file with module import 3. Regular file without - * imports and exports but module block encapsulation 4. regular file with module import - * containing a module block encapsulation + * Helper method executing a benchmark for a main .js-file and a module. The result is printed + * to the console with a summary statistic. The time unit is 10 ns. + * + * @param main + * @param module + * @throws IOException */ - @Test - public void testModuleBlockBenchmark() throws IOException { + private static void benchmark(String main, String module) throws IOException { + final int RUNS = 50; + final int WARMUP = 20; + + final long TIME_CONVERSION = 10; + File[] allFilesArray = null; TestOutput out = new TestOutput(); - long[] durations = new long[50]; + long[] durations = new long[RUNS]; long startTime, endTime; - long timeConversion = 10; - - System.out.println("Benchmark for module blocks with k-means algorithm: "); - - try (Context context = JSTest.newContextBuilder().allowHostAccess(HostAccess.ALL).allowIO(true).err(out).out(out).option( - JSContextOptions.CONSOLE_NAME, "true").option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").build()) { - allFilesArray = prepareTestFileAndModules("resources/moduleBlock/benchmark/kMeansRegular.js"); - - Source mainSource = Source.newBuilder(ID, allFilesArray[0]).mimeType("application/javascript+module").build(); - - // initial eval - context.eval(mainSource); - - // warmup - for (int i = 0; i < 20; i++) { - context.parse(mainSource); - context.eval(mainSource); - } - - // benchmark - for (int i = 0; i < durations.length; i++) { - startTime = System.nanoTime(); - - context.parse(mainSource); - context.eval(mainSource); - - endTime = System.nanoTime(); - - durations[i] = (endTime - startTime) / timeConversion; - } - - System.out.println("Regular kMeans execution: " + LongStream.of(durations).summaryStatistics()); - LongStream.of(durations).forEach(System.out::println); - } finally { - deleteFiles(allFilesArray); - } - - out = new TestOutput(); - - try (Context context = JSTest.newContextBuilder().allowHostAccess(HostAccess.ALL).allowIO(true).err(out).out(out).option( - JSContextOptions.CONSOLE_NAME, "true").option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").build()) { - allFilesArray = prepareTestFileAndModules("resources/moduleBlock/benchmark/kMeansModuleBlock.js"); - - Source mainSource = Source.newBuilder(ID, allFilesArray[0]).mimeType("application/javascript+module").build(); - - // initial eval - context.eval(mainSource); - - // warmup - for (int i = 0; i < 20; i++) { - context.parse(mainSource); - context.eval(mainSource); - } - - // benchmark - for (int i = 0; i < durations.length; i++) { - startTime = System.nanoTime(); - - context.parse(mainSource); - context.eval(mainSource); - - endTime = System.nanoTime(); - - durations[i] = (endTime - startTime) / timeConversion; - } - - System.out.println("ModuleBlock kMeans execution: " + LongStream.of(durations).summaryStatistics()); - LongStream.of(durations).forEach(System.out::println); - - } finally { - deleteFiles(allFilesArray); - } - - out = new TestOutput(); try (Context context = JSTest.newContextBuilder().allowHostAccess(HostAccess.ALL).allowIO(true).err(out).out(out).option( - JSContextOptions.CONSOLE_NAME, "true").option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").build()) { - allFilesArray = prepareTestFileAndModules("resources/moduleBlock/benchmark/kMeansModuleImport.js", - "resources/moduleBlock/benchmark/kMeansModule.js"); + JSContextOptions.CONSOLE_NAME, "true").option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").option(JSContextOptions.MODULE_BLOCKS_NAME, "true").build()) { + allFilesArray = prepareTestFileAndModules(main, module); Source mainSource = Source.newBuilder(ID, allFilesArray[0]).mimeType("application/javascript+module").build(); @@ -428,13 +310,13 @@ public void testModuleBlockBenchmark() throws IOException { context.eval(mainSource); // warmup - for (int i = 0; i < 20; i++) { + for (int i = 0; i < WARMUP; i++) { context.parse(mainSource); context.eval(mainSource); } // benchmark - for (int i = 0; i < durations.length; i++) { + for (int i = 0; i < RUNS; i++) { startTime = System.nanoTime(); context.parse(mainSource); @@ -442,127 +324,37 @@ public void testModuleBlockBenchmark() throws IOException { endTime = System.nanoTime(); - durations[i] = (endTime - startTime) / timeConversion; + durations[i] = (endTime - startTime) / TIME_CONVERSION; } - System.out.println("Module kMeans execution: " + LongStream.of(durations).summaryStatistics()); - LongStream.of(durations).forEach(System.out::println); - + System.out.println(main.substring(main.lastIndexOf("/") + 1) + " execution times: " + LongStream.of(durations).summaryStatistics()); } finally { deleteFiles(allFilesArray); } + } - out = new TestOutput(); - - try (Context context = JSTest.newContextBuilder().allowHostAccess(HostAccess.ALL).allowIO(true).err(out).out(out).option( - JSContextOptions.CONSOLE_NAME, "true").option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").build()) { - allFilesArray = prepareTestFileAndModules("resources/moduleBlock/benchmark/kMeansModuleModuleBlockImport.js", - "resources/moduleBlock/benchmark/kMeansModuleModuleBlock.js"); - - Source mainSource = Source.newBuilder(ID, allFilesArray[0]).mimeType("application/javascript+module").build(); - - // initial eval - context.eval(mainSource); - - // warmup - for (int i = 0; i < 20; i++) { - context.parse(mainSource); - context.eval(mainSource); - } - - // benchmark - for (int i = 0; i < durations.length; i++) { - startTime = System.nanoTime(); - - context.parse(mainSource); - context.eval(mainSource); - - endTime = System.nanoTime(); - - durations[i] = (endTime - startTime) / timeConversion; - } - - System.out.println("Module ModuleBlock kMeans execution: " + LongStream.of(durations).summaryStatistics()); - LongStream.of(durations).forEach(System.out::println); - - } finally { - deleteFiles(allFilesArray); - } - - System.out.println("Benchmark for module blocks with toy function returning 5:"); - - out = new TestOutput(); - - try (Context context = JSTest.newContextBuilder().allowHostAccess(HostAccess.ALL).allowIO(true).err(out).out(out).option( - JSContextOptions.CONSOLE_NAME, "true").option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").build()) { - allFilesArray = prepareTestFileAndModules("resources/moduleBlock/benchmark/toy/regular.js"); - - Source mainSource = Source.newBuilder(ID, allFilesArray[0]).mimeType("application/javascript+module").build(); - - // initial eval - context.eval(mainSource); - - // warmup - for (int i = 0; i < 20; i++) { - context.parse(mainSource); - context.eval(mainSource); - } - - // benchmark - for (int i = 0; i < durations.length; i++) { - startTime = System.nanoTime(); - - context.parse(mainSource); - context.eval(mainSource); - - endTime = System.nanoTime(); - - durations[i] = (endTime - startTime) / timeConversion; - } - - System.out.println("Regular toy function call: " + LongStream.of(durations).summaryStatistics()); - LongStream.of(durations).forEach(System.out::println); - - } finally { - deleteFiles(allFilesArray); - } - - out = new TestOutput(); - - try (Context context = JSTest.newContextBuilder().allowHostAccess(HostAccess.ALL).allowIO(true).err(out).out(out).option( - JSContextOptions.CONSOLE_NAME, "true").option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").build()) { - allFilesArray = prepareTestFileAndModules("resources/moduleBlock/benchmark/toy/regularModuleBlock.js"); - - Source mainSource = Source.newBuilder(ID, allFilesArray[0]).mimeType("application/javascript+module").build(); - - // initial eval - context.eval(mainSource); - - // warmup - for (int i = 0; i < 20; i++) { - context.parse(mainSource); - context.eval(mainSource); - } - - // benchmark - for (int i = 0; i < durations.length; i++) { - startTime = System.nanoTime(); + /** + * Benchmark test for overhead, is kept running 50 times each for comparison: 1. Regular file + * without imports and exports 2. Regular file with module import 3. Regular file without + * imports and exports but module block encapsulation 4. regular file with module import + * containing a module block encapsulation + */ + @Test + public void testModuleBlockBenchmark() throws IOException { + System.out.println("Benchmark for module blocks with k-means algorithm and a toy example: "); - context.parse(mainSource); - context.eval(mainSource); + benchmark("resources/moduleBlock/benchmark/kMeansRegular.js", "resources/moduleBlock/benchmark/kMeansRegular.js"); - endTime = System.nanoTime(); + benchmark("resources/moduleBlock/benchmark/kMeansModuleBlock.js", "resources/moduleBlock/benchmark/kMeansModuleBlock.js"); - durations[i] = (endTime - startTime) / timeConversion; - } + benchmark("resources/moduleBlock/benchmark/kMeansModuleImport.js", "resources/moduleBlock/benchmark/kMeansModule.js"); - System.out.println("Module block toy function call: " + LongStream.of(durations).summaryStatistics()); - LongStream.of(durations).forEach(System.out::println); + benchmark("resources/moduleBlock/benchmark/kMeansModuleModuleBlockImport.js", + "resources/moduleBlock/benchmark/kMeansModuleModuleBlock.js"); - } finally { - deleteFiles(allFilesArray); - } + benchmark("resources/moduleBlock/benchmark/toy/regular.js", "resources/moduleBlock/benchmark/toy/regular.js"); + benchmark("resources/moduleBlock/benchmark/toy/regularModuleBlock.js", "resources/moduleBlock/benchmark/toy/regularModuleBlock.js"); } /** @@ -596,7 +388,7 @@ public void testFunctionExportNoMimeType() throws IOException { String mainFilePath = allFilesArray[0].getAbsolutePath(); String[] mainFileBaseAndExtension = baseAndExtension(mainFilePath); File mainFileWithMjsExtension = new File(mainFileBaseAndExtension[0] + ".mjs"); - // noinspection ResultOfMethodCallIgnored + // no inspection ResultOfMethodCallIgnored allFilesArray[0].renameTo(mainFileWithMjsExtension); Source mainSource = Source.newBuilder(ID, mainFileWithMjsExtension).build(); Value v = context.eval(mainSource); 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 index e34d92b4295..7ab724d01e2 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -134,4 +134,4 @@ export function cluster() { stable = doNewClustering(); computeCentroids(); } -} \ 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/kMeansModuleBlock.js b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModuleBlock.js index d093c8218ff..8498a58ccd6 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -145,4 +145,4 @@ }; return await import(kMeans); -})(); \ 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/kMeansModuleImport.js b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModuleImport.js index dc294fd6e9c..54e44edb016 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -42,4 +42,4 @@ import * as module from 'kMeansModule.js'; module.createRandomData(); -module.cluster(); \ No newline at end of file +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 index 98f3fe0f907..6a8efee3260 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -145,4 +145,4 @@ export var moduleBlock = (async function() { }; return await import(kMeans); -}); \ 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/kMeansModuleModuleBlockImport.js b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/benchmark/kMeansModuleModuleBlockImport.js index 50da3ab873b..85d2d8a98a2 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -41,4 +41,4 @@ import * as module from 'kMeansModuleModuleBlock.js'; -module.moduleBlock(); \ No newline at end of file +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 index 01022d5b566..4423d6a7ace 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -137,4 +137,4 @@ function cluster() { } createRandomData(); -cluster(); \ No newline at end of file +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 index 32d8cf87ad6..ff0be296bd9 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -43,4 +43,5 @@ return 2+3; } - simple(); \ No newline at end of file + 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 index 1b15fd63d58..819950aa362 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -45,4 +45,4 @@ return await import(moduleBlock); })(); -simple.then(value => value.t+2); \ No newline at end of file +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 index dd005b94cf9..f1342873a7e 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -62,4 +62,12 @@ var five = test.then( function(moduleBlock) { return moduleBlock.resolved; }).then(resolved => resolved+1); -[five]; \ No newline at end of file +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 index fb360a474bc..3c6fd68c09b 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -68,6 +68,14 @@ 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 /* @@ -86,4 +94,4 @@ console.assert(m.o !== m1.o, "Both o's are equal."); })(); -*/ \ 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/moduleBlockFunctionExportTestMimic.js b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockFunctionExportTestMimic.js index 8da65402a27..1216095a6a5 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -67,4 +67,4 @@ 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]; \ No newline at end of file +[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 index dd3ef6c1046..dcaeb262538 100644 --- 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 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2020, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -86,4 +86,4 @@ if (moduleBlock.constructor.prototype === Object.prototype) { st = 0; } -[sq, dg, st]; \ No newline at end of file +[sq, dg, st]; 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 ff8d6ea795e..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,7 +322,7 @@ public enum Constructor implements BuiltinEnum { // --- not new.target-capable below --- TypedArray(0), Symbol(0), - ModuleBlock(1), + ModuleBlock(0), // non-standard (Nashorn) extensions JSAdapter(1), 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 index 5bb956dccf9..b2fd6cb8aa1 100644 --- 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 @@ -1,13 +1,49 @@ +/* + * 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 com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.object.DynamicObjectLibrary; -import com.oracle.truffle.js.builtins.ArrayIteratorPrototypeBuiltinsFactory.ArrayIteratorNextNodeGen; -import com.oracle.truffle.js.builtins.ArrayPrototypeBuiltinsFactory.JSArrayToStringNodeGen; import com.oracle.truffle.js.builtins.ModuleBlockPrototypeBuiltinsFactory.JSModuleBlockToStringNodeGen; -import com.oracle.truffle.js.builtins.DatePrototypeBuiltins.JSDateOperation; -import com.oracle.truffle.js.nodes.access.HasHiddenKeyCacheNode; import com.oracle.truffle.js.nodes.access.PropertyGetNode; import com.oracle.truffle.js.nodes.function.JSBuiltin; import com.oracle.truffle.js.nodes.function.JSBuiltinNode; @@ -15,9 +51,7 @@ import com.oracle.truffle.js.runtime.Errors; import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.builtins.BuiltinEnum; -import com.oracle.truffle.js.runtime.builtins.JSDate; import com.oracle.truffle.js.runtime.builtins.JSModuleBlock; -import com.oracle.truffle.js.runtime.util.WeakMap; /** * Contains builtins for %ModuleBlock%.prototype. @@ -55,8 +89,6 @@ protected Object createNode(JSContext context, JSBuiltin builtin, boolean constr } public abstract static class JSModuleBlockToStringNode extends JSBuiltinNode { - - JSContext context_; DynamicObject prototype; public JSModuleBlockToStringNode(JSContext context, JSBuiltin builtin) { @@ -65,10 +97,9 @@ public JSModuleBlockToStringNode(JSContext context, JSBuiltin builtin) { prototype = context.getRealm().getModuleBlockPrototype(); } - // TODO @Specialization(guards = "isJSOrdinaryObject(thisModuleBlock)") protected String doOperation(Object thisModuleBlock) { - // TODO Type check, then check for hidden property body and return hidden property + // Type check, then check for hidden property body and return hidden property // sourceText if (DynamicObjectLibrary.getUncached().containsKey((DynamicObject) thisModuleBlock, (Object) ModuleBlockNode.getModuleBodyKey())) { @@ -77,7 +108,7 @@ protected String doOperation(Object thisModuleBlock) { Object sourceCode = getSourceCode.getValue(thisModuleBlock); return "module {" + sourceCode.toString() + " }"; - } else if (thisModuleBlock.equals(this.getContext().getRealm().getModuleBlockPrototype())) { + } else if (thisModuleBlock.equals(prototype)) { return JSModuleBlock.PROTOTYPE_NAME; } 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 index d32233749fd..3359a66d896 100644 --- 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 @@ -1,3 +1,43 @@ +/* + * 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; @@ -11,8 +51,6 @@ public class ModuleBlockNode extends JavaScriptNode { public static final String TYPE_NAME = "moduleBlock"; - public static final String CLASS_NAME = "ModuleBlock"; - public static final String PROTOTYPE_NAME = "ModuleBlock.prototype"; static final HiddenKey SOURCE_KEY = new HiddenKey("SourceText"); static final HiddenKey MODULE_BODY_KEY = new HiddenKey("ModuleBlockBody"); 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 9e4d2c81606..cb3fc4730ce 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 @@ -70,6 +70,7 @@ 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.PromiseCapabilityRecord; import com.oracle.truffle.js.runtime.objects.PromiseReactionRecord; import com.oracle.truffle.js.runtime.objects.ScriptOrModule; @@ -134,6 +135,18 @@ public Object execute(VirtualFrame frame) { Source source = Source.newBuilder(JavaScriptLanguage.ID, sourceText.toString(), (String) moduleBlockName).build(); + // TODO + /* + * System.out.println("TESTING: " + JSObject.hasProperty((DynamicObject) specifier, + * ModuleBlockNode.getModuleBodyKey().getName())); System.out.println("TESTING2: " + + * JSObject.isJSObject(specifier)); JSObject.ownPropertyKeys((DynamicObject) + * specifier).stream().forEach(System.out::println); System.out.println("Keys: " + + * JSObject.ownPropertyKeys((DynamicObject) specifier).size()); + * + * System.out.println("Length: " + JSObject.getKeyArray((DynamicObject) + * specifier).length); + */ + return hostImportModuleDynamically(referencingScriptOrModule, specifier, source); } @@ -221,18 +234,18 @@ public DynamicObject createImportModuleDynamicallyJob(ScriptOrModule referencing if (context.isOptionTopLevelAwait()) { Triple request = new Triple<>(referencingScriptOrModule, specifier, promiseCapability); PromiseCapabilityRecord startModuleLoadCapability = newPromiseCapability(); - PromiseReactionRecord startModuleLoad = PromiseReactionRecord.create(startModuleLoadCapability, createImportModuleDynamicallyHandler(RootType.TLA), 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(RootType.IMD), 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.MB), true), request); + return promiseReactionJobNode.execute(PromiseReactionRecord.create(promiseCapability, createImportModuleDynamicallyHandler(RootType.ModuleBlock), true), request); } /** @@ -245,9 +258,9 @@ private DynamicObject createImportModuleDynamicallyHandler(RootType root) { } private static enum RootType { - IMD, - TLA, - MB; + ImportModuleDynamically, + TopLevelAwait, + ModuleBlock; } private static JSFunctionData createImportModuleDynamicallyHandlerImpl(JSContext context, RootType type) { @@ -338,12 +351,18 @@ class ModuleBlockRootNode extends JavaScriptRootNode { @Override public Object execute(VirtualFrame frame) { - @SuppressWarnings("unchecked") - Triple request = (Triple) argumentNode.execute(frame); + // @SuppressWarnings("unchecked") + assert argumentNode.execute(frame) instanceof Triple; + Triple request = (Triple) argumentNode.execute(frame); - ScriptOrModule referencingScriptOrModule = request.getFirst(); - DynamicObject moduleBlock = request.getSecond(); - Source source = request.getThird(); + 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); @@ -369,13 +388,13 @@ protected Object finishDynamicImport(JSRealm realm, JSModuleRecord moduleRecord, JavaScriptRootNode root; switch (type) { - case TLA: + case TopLevelAwait: root = new TopLevelAwaitImportModuleDynamicallyRootNode(); break; - case IMD: + case ImportModuleDynamically: root = new ImportModuleDynamicallyRootNode(); break; - case MB: + case ModuleBlock: root = new ModuleBlockRootNode(); break; default: 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..561fdbbb16a 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,10 @@ 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 enum UnhandledRejectionsTrackingMode { NONE, WARN, @@ -613,6 +617,7 @@ private void cacheOptions() { this.webAssembly = readBooleanOption(WEBASSEMBLY); this.unhandledRejectionsMode = readUnhandledRejectionsMode(); this.newSetMethods = readBooleanOption(NEW_SET_METHODS); + this.moduleBlocks = readBooleanOption(MODULE_BLOCKS); this.operatorOverloading = readBooleanOption(OPERATOR_OVERLOADING); this.propertyCacheLimit = readIntegerOption(PROPERTY_CACHE_LIMIT); @@ -984,6 +989,10 @@ public boolean isNewSetMethods() { return newSetMethods; } + public boolean isModuleBlocks() { + return moduleBlocks; + } + public boolean isOperatorOverloading() { return operatorOverloading; } @@ -1040,6 +1049,7 @@ 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.operatorOverloading ? 1 : 0); return hash; } @@ -1200,6 +1210,9 @@ public boolean equals(Object obj) { if (this.newSetMethods != other.newSetMethods) { return false; } + if (this.moduleBlocks != other.moduleBlocks) { + 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 c95da878607..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 @@ -2473,11 +2473,8 @@ public DynamicObject getForeignIterablePrototype() { return foreignIterablePrototype; } - // TODO private boolean isModuleBlockAvailable() { - return true; - // return truffleLanguageEnv.isPolyglotBindingsAccessAllowed() && - // truffleLanguageEnv.getInternalLanguages().get("moduleBlock") != null; + return getContext().getContextOptions().isModuleBlocks(); } public final DynamicObject getModuleBlockConstructor() { 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 index e0061721b25..24f21ac981d 100644 --- 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 @@ -1,3 +1,43 @@ +/* + * 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; 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 index 5860a69efb1..c9c20d0f72a 100644 --- 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 @@ -1,3 +1,43 @@ +/* + * 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; From 823a95b3d5757174957f431f9eba57b226e0de58 Mon Sep 17 00:00:00 2001 From: KamikazeSquirrel <64982603+KamikazeSquirrel@users.noreply.github.com> Date: Tue, 27 Jul 2021 08:48:57 +0200 Subject: [PATCH 4/8] second suggestion implementation Changed DynamicObjectLibrary code to JSObjectUtilCode, added an assertion and activated an Error. --- .../truffle/js/builtins/GlobalBuiltins.java | 7 +++++-- .../builtins/ModuleBlockPrototypeBuiltins.java | 4 +++- .../js/nodes/promise/ImportCallNode.java | 18 ++++-------------- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/GlobalBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/GlobalBuiltins.java index 898400c2f2f..b53c7eb0c1b 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 @@ -1309,6 +1309,7 @@ protected JSGlobalSerializeNode(JSContext context, JSBuiltin builtin) { super(context, builtin); } + @Specialization protected byte[] serialize(Object value) { if (DynamicObjectLibrary.getUncached().containsKey((DynamicObject) value, (Object) ModuleBlockNode.getModuleBodyKey())) { PropertyGetNode getSourceCode = PropertyGetNode.createGetHidden(ModuleBlockNode.getModuleSourceKey(), getContext()); @@ -1318,7 +1319,7 @@ protected byte[] serialize(Object value) { return ("module {" + sourceCode.toString() + "}").getBytes(); } - // TODO Errors.createTypeError("Not a ModuleBlock"); + Errors.createTypeError("Not a ModuleBlock"); return null; } @@ -1333,10 +1334,12 @@ protected JSGlobalDeserializeNode(JSContext context, JSBuiltin builtin) { super(context, builtin); } + @Specialization protected JavaScriptNode deserialize(Object value) { + assert value instanceof byte[]; String sourceCode = new String((byte[]) value, StandardCharsets.UTF_8); - // get from sourcecode string to module block via parsing and then translating + // turn from sourcecode string to module block via parsing and then translating Source source = Source.newBuilder(JavaScriptLanguage.ID, sourceCode, "moduleBlock").build(); 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 index b2fd6cb8aa1..041a28ecbac 100644 --- 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 @@ -52,6 +52,7 @@ import com.oracle.truffle.js.runtime.JSContext; import com.oracle.truffle.js.runtime.builtins.BuiltinEnum; import com.oracle.truffle.js.runtime.builtins.JSModuleBlock; +import com.oracle.truffle.js.runtime.objects.JSObjectUtil; /** * Contains builtins for %ModuleBlock%.prototype. @@ -102,7 +103,8 @@ protected String doOperation(Object thisModuleBlock) { // Type check, then check for hidden property body and return hidden property // sourceText - if (DynamicObjectLibrary.getUncached().containsKey((DynamicObject) thisModuleBlock, (Object) ModuleBlockNode.getModuleBodyKey())) { + if (JSObjectUtil.hasHiddenProperty((DynamicObject) thisModuleBlock, + ModuleBlockNode.getModuleBodyKey())) { PropertyGetNode getSourceCode = PropertyGetNode.createGetHidden(ModuleBlockNode.getModuleSourceKey(), this.getContext()); Object sourceCode = getSourceCode.getValue(thisModuleBlock); 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 cb3fc4730ce..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 @@ -53,6 +53,7 @@ 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; @@ -71,6 +72,7 @@ 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; @@ -120,7 +122,8 @@ public Object execute(VirtualFrame frame) { Object specifier = argRefNode.execute(frame); String specifierString; - if (specifier instanceof DynamicObject && DynamicObjectLibrary.getUncached().containsKey((DynamicObject) specifier, (Object) ModuleBlockNode.getModuleBodyKey())) { + 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); @@ -135,18 +138,6 @@ public Object execute(VirtualFrame frame) { Source source = Source.newBuilder(JavaScriptLanguage.ID, sourceText.toString(), (String) moduleBlockName).build(); - // TODO - /* - * System.out.println("TESTING: " + JSObject.hasProperty((DynamicObject) specifier, - * ModuleBlockNode.getModuleBodyKey().getName())); System.out.println("TESTING2: " + - * JSObject.isJSObject(specifier)); JSObject.ownPropertyKeys((DynamicObject) - * specifier).stream().forEach(System.out::println); System.out.println("Keys: " + - * JSObject.ownPropertyKeys((DynamicObject) specifier).size()); - * - * System.out.println("Length: " + JSObject.getKeyArray((DynamicObject) - * specifier).length); - */ - return hostImportModuleDynamically(referencingScriptOrModule, specifier, source); } @@ -351,7 +342,6 @@ class ModuleBlockRootNode extends JavaScriptRootNode { @Override public Object execute(VirtualFrame frame) { - // @SuppressWarnings("unchecked") assert argumentNode.execute(frame) instanceof Triple; Triple request = (Triple) argumentNode.execute(frame); From 71c872ca814e8842d139746b01ffe559bbbb7804 Mon Sep 17 00:00:00 2001 From: KamikazeSquirrel <64982603+KamikazeSquirrel@users.noreply.github.com> Date: Thu, 29 Jul 2021 10:37:30 +0200 Subject: [PATCH 5/8] added tests and contextOption for serialization api --- .../truffle/js/test/interop/ESModuleTest.java | 22 +++++++- .../moduleblock/moduleBlockSerialize.js | 52 +++++++++++++++++++ .../moduleblock/moduleBlockSerializeModule.js | 44 ++++++++++++++++ .../moduleblock/moduleBlockToString.js | 52 +++++++++++++++++++ .../truffle/js/builtins/GlobalBuiltins.java | 18 +++++-- .../oracle/truffle/js/runtime/JSContext.java | 4 ++ .../truffle/js/runtime/JSContextOptions.java | 14 +++++ 7 files changed, 202 insertions(+), 4 deletions(-) create mode 100644 graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockSerialize.js create mode 100644 graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockSerializeModule.js create mode 100644 graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/resources/moduleblock/moduleBlockToString.js diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ESModuleTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ESModuleTest.java index c11f0339cdb..7f5d6173c92 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ESModuleTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ESModuleTest.java @@ -220,7 +220,9 @@ private static void testModuleBlockMainMethod(String main, String module) throws TestOutput out = new TestOutput(); try (Context context = JSTest.newContextBuilder().allowHostAccess(HostAccess.ALL).allowIO(true).err(out).out(out).option( - JSContextOptions.CONSOLE_NAME, "true").option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").option(JSContextOptions.MODULE_BLOCKS_NAME, "true").build()) { + JSContextOptions.CONSOLE_NAME, "true").option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").option(JSContextOptions.EXPERIMENTAL_MODULE_BLOCK_SERIALIZATION_API, + "true").option( + JSContextOptions.MODULE_BLOCKS_NAME, "true").build()) { allFilesArray = prepareTestFileAndModules(main, module); Source mainSource = Source.newBuilder(ID, allFilesArray[0]).mimeType("application/javascript+module").build(); @@ -279,6 +281,24 @@ public void testModuleBlockComparison() throws IOException { "resources/functionexportmodule.js"); } + /** + * Test serialize and deserialize + */ + @Test + public void testSerializationFramework() throws IOException { + testModuleBlockMainMethod("resources/moduleBlock/moduleBlockSerialize.js", + "resources/moduleBlock/moduleBlockSerializeModule.js"); + } + + /** + * Test module block toString + */ + @Test + public void testModuleBlocktoString() throws IOException { + testModuleBlockMainMethod("resources/moduleBlock/moduleBlockToString.js", + "resources/functionexportmodule.js"); + } + /** * Helper method executing a benchmark for a main .js-file and a module. The result is printed * to the console with a summary statistic. The time unit is 10 ns. 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..a07d810094f --- /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 module from 'moduleBlockSerializeModule.js'; + +var moduleImport = (async function() { + const thing = deserialize(module.moduleBlock); + + return await import(thing); +})(); + +var five = moduleImport.then(value => value.test); + +[121,five,11]; 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..da1b95f87c8 --- /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,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. + */ + +//var moduleTest = module { export var test = 5; }; + +export var moduleBlock = serialize(module { }); 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..865d962ae1f --- /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,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. + */ + +var moduleBlockOne = module { export var test = 42; }; + +var one = 0; + +if (moduleBlockOne.toString() === "module { export var test = 42; }") { + one = 5; +} else { + one = 0; +} + +[121,one,11]; 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 b53c7eb0c1b..bc6a6ec09b8 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 @@ -103,6 +103,8 @@ import com.oracle.truffle.js.builtins.GlobalBuiltinsFactory.JSGlobalReadFullyNodeGen; import com.oracle.truffle.js.builtins.GlobalBuiltinsFactory.JSGlobalReadLineNodeGen; import com.oracle.truffle.js.builtins.GlobalBuiltinsFactory.JSGlobalUnEscapeNodeGen; +import com.oracle.truffle.js.builtins.GlobalBuiltinsFactory.JSGlobalSerializeNodeGen; +import com.oracle.truffle.js.builtins.GlobalBuiltinsFactory.JSGlobalDeserializeNodeGen; import com.oracle.truffle.js.builtins.commonjs.GlobalCommonJSRequireBuiltins; import com.oracle.truffle.js.builtins.helper.FloatParser; import com.oracle.truffle.js.builtins.helper.StringEscape; @@ -1305,13 +1307,18 @@ public boolean isCallerSensitive() { */ public abstract static class JSGlobalSerializeNode extends JSBuiltinNode { + protected JSContext context_; + protected JSGlobalSerializeNode(JSContext context, JSBuiltin builtin) { super(context, builtin); + context_ = context; } - @Specialization + @Specialization(guards = "context_.isExperimentalModuleBlocks()") protected byte[] serialize(Object value) { - if (DynamicObjectLibrary.getUncached().containsKey((DynamicObject) value, (Object) ModuleBlockNode.getModuleBodyKey())) { + assert value instanceof DynamicObject; + if (JSObjectUtil.hasHiddenProperty((DynamicObject) value, + ModuleBlockNode.getModuleBodyKey())) { PropertyGetNode getSourceCode = PropertyGetNode.createGetHidden(ModuleBlockNode.getModuleSourceKey(), getContext()); Object sourceCode = getSourceCode.getValue(value); @@ -1330,11 +1337,14 @@ protected byte[] serialize(Object value) { */ public abstract static class JSGlobalDeserializeNode extends JSBuiltinNode { + protected JSContext context_; + protected JSGlobalDeserializeNode(JSContext context, JSBuiltin builtin) { super(context, builtin); + context_ = context; } - @Specialization + @Specialization(guards = "context_.isExperimentalModuleBlocks()") protected JavaScriptNode deserialize(Object value) { assert value instanceof byte[]; String sourceCode = new String((byte[]) value, StandardCharsets.UTF_8); @@ -1343,6 +1353,8 @@ protected JavaScriptNode deserialize(Object value) { Source source = Source.newBuilder(JavaScriptLanguage.ID, sourceCode, "moduleBlock").build(); + System.out.println(source.getCharacters()); + return getContext().getEvaluator().parseModuleBlock(getContext(), source); } } 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 a98eca5b8dd..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 @@ -1744,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 561fdbbb16a..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 @@ -502,6 +502,11 @@ public Map apply(String value) { @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, @@ -618,6 +623,7 @@ private void cacheOptions() { 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); @@ -993,6 +999,10 @@ public boolean isModuleBlocks() { return moduleBlocks; } + public boolean isExperimentalModuleBlocks() { + return moduleBlocksSerializationAPI; + } + public boolean isOperatorOverloading() { return operatorOverloading; } @@ -1050,6 +1060,7 @@ public int hashCode() { 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; } @@ -1213,6 +1224,9 @@ public boolean equals(Object obj) { if (this.moduleBlocks != other.moduleBlocks) { return false; } + if (this.moduleBlocksSerializationAPI != other.moduleBlocksSerializationAPI) { + return false; + } if (this.operatorOverloading != other.operatorOverloading) { return false; } From e2e2500f923e91d935ec62fc0f675f681e1f3edc Mon Sep 17 00:00:00 2001 From: KamikazeSquirrel <64982603+KamikazeSquirrel@users.noreply.github.com> Date: Fri, 30 Jul 2021 19:20:07 +0200 Subject: [PATCH 6/8] api changes on deserialize --- .../js/parser/JavaScriptTranslator.java | 2 + .../ModuleBlockSerializationAPITest.java | 91 ++++++++++++++++++ .../truffle/js/test/interop/ESModuleTest.java | 3 +- .../moduleblock/moduleBlockSerialize.js | 14 +-- .../moduleblock/moduleBlockSerializeModule.js | 6 +- .../moduleblock/moduleBlockToString.js | 11 ++- .../truffle/js/builtins/GlobalBuiltins.java | 70 +------------- .../ModuleBlockPrototypeBuiltins.java | 93 ++++++++++++++++++- 8 files changed, 208 insertions(+), 82 deletions(-) create mode 100644 graal-js/src/com.oracle.truffle.js.test.threading/src/com/oracle/truffle/js/test/threading/ModuleBlockSerializationAPITest.java diff --git a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/JavaScriptTranslator.java b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/JavaScriptTranslator.java index 9e2014ec63e..6cb3ab161c8 100644 --- a/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/JavaScriptTranslator.java +++ b/graal-js/src/com.oracle.truffle.js.parser/src/com/oracle/truffle/js/parser/JavaScriptTranslator.java @@ -122,6 +122,8 @@ public static JavaScriptNode translateModuleBlock(NodeFactory factory, JSContext FunctionNode parsed = GraalJSParserHelper.parseModule(context, source, context.getParserOptions().putStrict(true)); JavaScriptTranslator translator = new JavaScriptTranslator(factory, context, source, 0, null, true); + FunctionRootNode functionRoot = translator.translateModule(parsed); // <- works + return translator.enterFunctionNode(parsed); } diff --git a/graal-js/src/com.oracle.truffle.js.test.threading/src/com/oracle/truffle/js/test/threading/ModuleBlockSerializationAPITest.java b/graal-js/src/com.oracle.truffle.js.test.threading/src/com/oracle/truffle/js/test/threading/ModuleBlockSerializationAPITest.java new file mode 100644 index 00000000000..740034b3b4e --- /dev/null +++ b/graal-js/src/com.oracle.truffle.js.test.threading/src/com/oracle/truffle/js/test/threading/ModuleBlockSerializationAPITest.java @@ -0,0 +1,91 @@ +package com.oracle.truffle.js.test.threading; + +import static org.junit.Assert.assertEquals; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; + +import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.HostAccess; +import org.graalvm.polyglot.Value; +import org.junit.Test; + +public class ModuleBlockSerializationAPITest { + /** + * 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 pingPong() { + 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.sent, 128); + assertEquals(c.received, 128); + } + + static class Producer extends Thread { + + private int sent; + private final BlockingQueue queue; + + Producer(BlockingQueue queue) { + this.queue = queue; + } + + @Override + public void run() { + Context cx = TestUtil.newContextBuilder().allowHostAccess(HostAccess.ALL).build(); + cx.getBindings("js").putMember("queue", queue); + try { + sent = cx.eval("js", " var sent = 0;" + + "for(var i = 0; i < 127; i++) {" + + " queue.put(JSON.stringify({message:i}));" + + " sent++;" + + "};" + + "queue.put(JSON.stringify({message:'byebye'}));" + + "++sent;").asInt(); + } finally { + cx.close(); + } + } + + } + + class Consumer extends Thread { + + private int received; + private final BlockingQueue queue; + + Consumer(BlockingQueue queue) { + this.queue = queue; + } + + @Override + public void run() { + Context cx = TestUtil.newContextBuilder().allowHostAccess(HostAccess.ALL).build(); + cx.getBindings("js").putMember("queue", queue); + try { + received = cx.eval("js", "var received = 0;" + + "do {" + + " var str = queue.take();" + + " received++;" + + " var m = JSON.parse(str);" + + "} while (m.message != 'byebye');" + + "received;").asInt(); + } finally { + cx.close(); + } + } + } +} diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ESModuleTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ESModuleTest.java index 7f5d6173c92..13ae3c3bd55 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ESModuleTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ESModuleTest.java @@ -221,8 +221,7 @@ private static void testModuleBlockMainMethod(String main, String module) throws TestOutput out = new TestOutput(); try (Context context = JSTest.newContextBuilder().allowHostAccess(HostAccess.ALL).allowIO(true).err(out).out(out).option( JSContextOptions.CONSOLE_NAME, "true").option(JSContextOptions.UNHANDLED_REJECTIONS_NAME, "throw").option(JSContextOptions.EXPERIMENTAL_MODULE_BLOCK_SERIALIZATION_API, - "true").option( - JSContextOptions.MODULE_BLOCKS_NAME, "true").build()) { + "true").option(JSContextOptions.MODULE_BLOCKS_NAME, "true").build()) { allFilesArray = prepareTestFileAndModules(main, module); Source mainSource = Source.newBuilder(ID, allFilesArray[0]).mimeType("application/javascript+module").build(); 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 index a07d810094f..29db9054cfb 100644 --- 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 @@ -39,14 +39,14 @@ * SOFTWARE. */ -import * as module from 'moduleBlockSerializeModule.js'; +import * as modules from 'moduleBlockSerializeModule.js'; -var moduleImport = (async function() { - const thing = deserialize(module.moduleBlock); +console.log(modules.moduleBlock); - return await import(thing); -})(); +var tester = ModuleBlock.prototype.deserialize(modules.moduleBlock); -var five = moduleImport.then(value => value.test); +var isIt = tester.test; -[121,five,11]; +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 index da1b95f87c8..5e7201e7900 100644 --- 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 @@ -39,6 +39,8 @@ * SOFTWARE. */ -//var moduleTest = module { export var test = 5; }; +var moduleTest = module { export var test = 5; }; -export var moduleBlock = serialize(module { }); +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 index 865d962ae1f..304b289200e 100644 --- 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 @@ -42,6 +42,7 @@ var moduleBlockOne = module { export var test = 42; }; var one = 0; +var two = 0; if (moduleBlockOne.toString() === "module { export var test = 42; }") { one = 5; @@ -49,4 +50,12 @@ if (moduleBlockOne.toString() === "module { export var test = 42; }") { one = 0; } -[121,one,11]; +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/GlobalBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/GlobalBuiltins.java index bc6a6ec09b8..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 @@ -103,8 +103,6 @@ import com.oracle.truffle.js.builtins.GlobalBuiltinsFactory.JSGlobalReadFullyNodeGen; import com.oracle.truffle.js.builtins.GlobalBuiltinsFactory.JSGlobalReadLineNodeGen; import com.oracle.truffle.js.builtins.GlobalBuiltinsFactory.JSGlobalUnEscapeNodeGen; -import com.oracle.truffle.js.builtins.GlobalBuiltinsFactory.JSGlobalSerializeNodeGen; -import com.oracle.truffle.js.builtins.GlobalBuiltinsFactory.JSGlobalDeserializeNodeGen; import com.oracle.truffle.js.builtins.commonjs.GlobalCommonJSRequireBuiltins; import com.oracle.truffle.js.builtins.helper.FloatParser; import com.oracle.truffle.js.builtins.helper.StringEscape; @@ -181,10 +179,6 @@ public enum Global implements BuiltinEnum { decodeURIComponent(1), eval(1), - // ModuleBlock methods - serialize(1), - deserialize(1), - // Annex B escape(1), unescape(1); @@ -227,12 +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 serialize: - return JSGlobalSerializeNodeGen.create(context, builtin, - args().fixedArgs(1).createArgumentNodes(context)); - case deserialize: - return JSGlobalDeserializeNodeGen.create(context, builtin, - args().fixedArgs(1).createArgumentNodes(context)); + case escape: return JSGlobalUnEscapeNodeGen.create(context, builtin, false, args().fixedArgs(1).createArgumentNodes(context)); case unescape: @@ -1302,63 +1291,6 @@ public boolean isCallerSensitive() { } } - /** - * 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 byte[] serialize(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 ("module {" + sourceCode.toString() + "}").getBytes(); - } - - 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 JavaScriptNode deserialize(Object value) { - assert value instanceof byte[]; - String sourceCode = new String((byte[]) value, StandardCharsets.UTF_8); - - // turn from sourcecode string to module block via parsing and then translating - - Source source = Source.newBuilder(JavaScriptLanguage.ID, sourceCode, "moduleBlock").build(); - - System.out.println(source.getCharacters()); - - return getContext().getEvaluator().parseModuleBlock(getContext(), source); - } - } - /** * Implementation of ECMAScript 5.1 B.2.1 escape() method and of ECMAScript 5.1 B.2.2 unescape() * method. 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 index 041a28ecbac..f9a1d1c752e 100644 --- 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 @@ -40,18 +40,29 @@ */ 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.builtins.BuiltinEnum; 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; /** @@ -66,7 +77,10 @@ protected ModuleBlockPrototypeBuiltins() { } public enum ModuleBlockPrototype implements BuiltinEnum { - toString(0); + toString(0), + // ModuleBlock methods + serialize(1), + deserialize(1); private final int length; @@ -85,6 +99,12 @@ protected Object createNode(JSContext context, JSBuiltin builtin, boolean constr 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; } @@ -103,6 +123,8 @@ protected String doOperation(Object thisModuleBlock) { // Type check, then check for hidden property body and return hidden property // sourceText + System.out.println("In toString."); + if (JSObjectUtil.hasHiddenProperty((DynamicObject) thisModuleBlock, ModuleBlockNode.getModuleBodyKey())) { PropertyGetNode getSourceCode = PropertyGetNode.createGetHidden(ModuleBlockNode.getModuleSourceKey(), this.getContext()); @@ -125,4 +147,73 @@ protected static boolean notJSModuleBlock(Object thisModuleBlock) { } } + + /** + * 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()); + } else { + return "Can't touch this"; + } + + // 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) { + System.out.println("In deserialize node. " + value.toString()); + + assert value instanceof String; + String sourceCode = (String) value;// new String((byte[]) value, + // StandardCharsets.UTF_8); + + // 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 From cd9e40b2111142396b3064590bd41e1165b34efe Mon Sep 17 00:00:00 2001 From: KamikazeSquirrel <64982603+KamikazeSquirrel@users.noreply.github.com> Date: Tue, 3 Aug 2021 10:41:18 +0200 Subject: [PATCH 7/8] serialization api String version and thread tests --- .../ModuleBlockSerializationAPITest.java | 91 ---------- .../truffle/js/test/interop/ESModuleTest.java | 169 +++++++++++++++++- .../ModuleBlockPrototypeBuiltins.java | 20 +-- 3 files changed, 170 insertions(+), 110 deletions(-) delete mode 100644 graal-js/src/com.oracle.truffle.js.test.threading/src/com/oracle/truffle/js/test/threading/ModuleBlockSerializationAPITest.java diff --git a/graal-js/src/com.oracle.truffle.js.test.threading/src/com/oracle/truffle/js/test/threading/ModuleBlockSerializationAPITest.java b/graal-js/src/com.oracle.truffle.js.test.threading/src/com/oracle/truffle/js/test/threading/ModuleBlockSerializationAPITest.java deleted file mode 100644 index 740034b3b4e..00000000000 --- a/graal-js/src/com.oracle.truffle.js.test.threading/src/com/oracle/truffle/js/test/threading/ModuleBlockSerializationAPITest.java +++ /dev/null @@ -1,91 +0,0 @@ -package com.oracle.truffle.js.test.threading; - -import static org.junit.Assert.assertEquals; - -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.BlockingQueue; - -import org.graalvm.polyglot.Context; -import org.graalvm.polyglot.HostAccess; -import org.graalvm.polyglot.Value; -import org.junit.Test; - -public class ModuleBlockSerializationAPITest { - /** - * 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 pingPong() { - 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.sent, 128); - assertEquals(c.received, 128); - } - - static class Producer extends Thread { - - private int sent; - private final BlockingQueue queue; - - Producer(BlockingQueue queue) { - this.queue = queue; - } - - @Override - public void run() { - Context cx = TestUtil.newContextBuilder().allowHostAccess(HostAccess.ALL).build(); - cx.getBindings("js").putMember("queue", queue); - try { - sent = cx.eval("js", " var sent = 0;" + - "for(var i = 0; i < 127; i++) {" + - " queue.put(JSON.stringify({message:i}));" + - " sent++;" + - "};" + - "queue.put(JSON.stringify({message:'byebye'}));" + - "++sent;").asInt(); - } finally { - cx.close(); - } - } - - } - - class Consumer extends Thread { - - private int received; - private final BlockingQueue queue; - - Consumer(BlockingQueue queue) { - this.queue = queue; - } - - @Override - public void run() { - Context cx = TestUtil.newContextBuilder().allowHostAccess(HostAccess.ALL).build(); - cx.getBindings("js").putMember("queue", queue); - try { - received = cx.eval("js", "var received = 0;" + - "do {" + - " var str = queue.take();" + - " received++;" + - " var m = JSON.parse(str);" + - "} while (m.message != 'byebye');" + - "received;").asInt(); - } finally { - cx.close(); - } - } - } -} diff --git a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ESModuleTest.java b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ESModuleTest.java index 13ae3c3bd55..a4b1adaab88 100644 --- a/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ESModuleTest.java +++ b/graal-js/src/com.oracle.truffle.js.test/src/com/oracle/truffle/js/test/interop/ESModuleTest.java @@ -76,6 +76,8 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; import java.util.stream.LongStream; /** @@ -232,9 +234,11 @@ private static void testModuleBlockMainMethod(String main, String module) throws assertTrue(v.hasArrayElements()); - System.out.println("Square test: " + v.getArrayElement(0)); - System.out.println("Diagonal test: " + v.getArrayElement(1)); - System.out.println("Sqrt test: " + v.getArrayElement(2)); + /* + * Test output: System.out.println("Square test: " + v.getArrayElement(0)); + * System.out.println("Diagonal test: " + v.getArrayElement(1)); + * System.out.println("Sqrt test: " + v.getArrayElement(2)); + */ assertTrue(v.getArrayElement(0).toString().contains("121")); assertTrue(v.getArrayElement(1).toString().contains("5")); @@ -346,7 +350,9 @@ private static void benchmark(String main, String module) throws IOException { durations[i] = (endTime - startTime) / TIME_CONVERSION; } - System.out.println(main.substring(main.lastIndexOf("/") + 1) + " execution times: " + LongStream.of(durations).summaryStatistics()); + // Test output + // System.out.println(main.substring(main.lastIndexOf("/") + 1) + " execution times: " + + // LongStream.of(durations).summaryStatistics()); } finally { deleteFiles(allFilesArray); } @@ -360,8 +366,6 @@ private static void benchmark(String main, String module) throws IOException { */ @Test public void testModuleBlockBenchmark() throws IOException { - System.out.println("Benchmark for module blocks with k-means algorithm and a toy example: "); - benchmark("resources/moduleBlock/benchmark/kMeansRegular.js", "resources/moduleBlock/benchmark/kMeansRegular.js"); benchmark("resources/moduleBlock/benchmark/kMeansModuleBlock.js", "resources/moduleBlock/benchmark/kMeansModuleBlock.js"); @@ -566,4 +570,157 @@ public Map 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/src/com/oracle/truffle/js/builtins/ModuleBlockPrototypeBuiltins.java b/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/builtins/ModuleBlockPrototypeBuiltins.java index f9a1d1c752e..07000108185 100644 --- 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 @@ -59,7 +59,9 @@ 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; @@ -122,9 +124,6 @@ public JSModuleBlockToStringNode(JSContext context, JSBuiltin builtin) { protected String doOperation(Object thisModuleBlock) { // Type check, then check for hidden property body and return hidden property // sourceText - - System.out.println("In toString."); - if (JSObjectUtil.hasHiddenProperty((DynamicObject) thisModuleBlock, ModuleBlockNode.getModuleBodyKey())) { PropertyGetNode getSourceCode = PropertyGetNode.createGetHidden(ModuleBlockNode.getModuleSourceKey(), this.getContext()); @@ -169,14 +168,12 @@ protected String doOperation(Object value) { Object sourceCode = getSourceCode.getValue(value); - return (sourceCode.toString()); - } else { - return "Can't touch this"; + return sourceCode.toString(); } - // Errors.createTypeError("Not a ModuleBlock"); + Errors.createTypeError("Not a ModuleBlock"); - // return null; + return null; } } @@ -194,14 +191,11 @@ protected JSGlobalDeserializeNode(JSContext context, JSBuiltin builtin) { @Specialization(guards = "context_.isExperimentalModuleBlocks()") protected Object doOperation(Object value) { - System.out.println("In deserialize node. " + value.toString()); - assert value instanceof String; - String sourceCode = (String) value;// new String((byte[]) value, - // StandardCharsets.UTF_8); - // turn from sourcecode string to module block via parsing and then translating + 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(); From 0eed18c94efa23a136e8eefa2e0327c2ddd359ac Mon Sep 17 00:00:00 2001 From: KamikazeSquirrel <64982603+KamikazeSquirrel@users.noreply.github.com> Date: Tue, 3 Aug 2021 19:54:04 +0200 Subject: [PATCH 8/8] added node example --- .../truffle/trufflenode/GraalJSAccess.java | 10 ++++++++++ .../test/graal/unit/workerModuleBlock.js | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 graal-nodejs/test/graal/unit/workerModuleBlock.js 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