From f29b8f6f5b1a15ea9c690b295d386c08a0a8353e Mon Sep 17 00:00:00 2001 From: Roland Schatz Date: Mon, 7 May 2018 14:50:24 +0200 Subject: [PATCH 1/8] Support KEYS message for SulongLibrary. --- .../truffle/llvm/runtime/LLVMScope.java | 21 +++++++++++-------- .../src/com/oracle/truffle/llvm/Runner.java | 8 +++++++ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/projects/com.oracle.truffle.llvm.runtime/src/com/oracle/truffle/llvm/runtime/LLVMScope.java b/projects/com.oracle.truffle.llvm.runtime/src/com/oracle/truffle/llvm/runtime/LLVMScope.java index cc9923249..8dc2d29fc 100644 --- a/projects/com.oracle.truffle.llvm.runtime/src/com/oracle/truffle/llvm/runtime/LLVMScope.java +++ b/projects/com.oracle.truffle.llvm.runtime/src/com/oracle/truffle/llvm/runtime/LLVMScope.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. * * All rights reserved. * @@ -161,10 +161,14 @@ private void register(String name, LLVMFunctionDescriptor descriptor) { } private void put(String name, LLVMFunctionDescriptor descriptor) { - assert !functions.containsKey(name) && !functionKeys.contains(name); + String realName = name; + if (realName.charAt(0) == '@') { + realName = realName.substring(1); + } + assert !functions.containsKey(name) && !functionKeys.contains(realName); assert functionKeys.size() == functions.size(); functions.put(name, descriptor); - functionKeys.add(name); + functionKeys.add(realName); } } @@ -258,12 +262,7 @@ public boolean test(TruffleObject receiver) { public abstract static class KeysOfLLVMScope extends Node { protected Object access(LLVMScope receiver) { - return getKeys(receiver); - } - - @TruffleBoundary - private static TruffleObject getKeys(LLVMScope scope) { - return new Keys(scope); + return receiver.getKeys(); } } @@ -283,6 +282,10 @@ protected Object access(LLVMScope scope, String globalName) { } } + public TruffleObject getKeys() { + return new Keys(this); + } + @MessageResolution(receiverType = Keys.class) static final class Keys implements TruffleObject { diff --git a/projects/com.oracle.truffle.llvm/src/com/oracle/truffle/llvm/Runner.java b/projects/com.oracle.truffle.llvm/src/com/oracle/truffle/llvm/Runner.java index ee4f492c1..5631713ba 100644 --- a/projects/com.oracle.truffle.llvm/src/com/oracle/truffle/llvm/Runner.java +++ b/projects/com.oracle.truffle.llvm/src/com/oracle/truffle/llvm/Runner.java @@ -219,6 +219,14 @@ Object access(SulongLibrary library, String name, Object[] arguments) { } } + @Resolve(message = "KEYS") + abstract static class KeysNode extends Node { + + TruffleObject access(SulongLibrary library) { + return library.scope.getKeys(); + } + } + @Resolve(message = "KEY_INFO") abstract static class KeyInfoNode extends Node { From d3892b2df7f08f9cd6346e429fbde4c39777643e Mon Sep 17 00:00:00 2001 From: Roland Schatz Date: Mon, 7 May 2018 15:57:24 +0200 Subject: [PATCH 2/8] Unwrap foreign objects when showing them in the debugger. --- .../intrinsics/llvm/debug/LLVMConstantValueProvider.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/llvm/debug/LLVMConstantValueProvider.java b/projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/llvm/debug/LLVMConstantValueProvider.java index 1857f530c..2b3b2821f 100644 --- a/projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/llvm/debug/LLVMConstantValueProvider.java +++ b/projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/llvm/debug/LLVMConstantValueProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, Oracle and/or its affiliates. + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. * * All rights reserved. * @@ -37,6 +37,7 @@ import com.oracle.truffle.llvm.runtime.debug.LLVMDebugTypeConstants; import com.oracle.truffle.llvm.runtime.debug.LLVMDebugValue; import com.oracle.truffle.llvm.runtime.floating.LLVM80BitFloat; +import com.oracle.truffle.llvm.runtime.interop.LLVMTypedForeignObject; import com.oracle.truffle.llvm.runtime.memory.LLVMMemory; import com.oracle.truffle.llvm.runtime.pointer.LLVMNativePointer; @@ -564,6 +565,9 @@ public boolean isInteropValue() { @Override public Object asInteropValue() { + if (value instanceof LLVMTypedForeignObject) { + return ((LLVMTypedForeignObject) value).getForeign(); + } return value; } } From aaa12f4e2f43e0b05e4044a02d0a83a81eb4f409 Mon Sep 17 00:00:00 2001 From: Roland Schatz Date: Mon, 7 May 2018 15:59:45 +0200 Subject: [PATCH 3/8] New builtin polyglot_eval_file. --- CHANGELOG.md | 1 + .../include/polyglot.h | 13 +++ .../intrinsics/interop/LLVMPolyglotEval.java | 102 ++++++++++++------ .../factories/NFIIntrinsicsProvider.java | 7 ++ 4 files changed, 91 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7d5fc4a5..6c6ba58c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ New features: * Use dynamic linker semantics when loading multiple bitcode files. * Support ELF files with embedded LLVM bitcode. +* New builtin polyglot_eval_file. Improvements: diff --git a/projects/com.oracle.truffle.llvm.libraries.bitcode/include/polyglot.h b/projects/com.oracle.truffle.llvm.libraries.bitcode/include/polyglot.h index 45057745e..51f3746a2 100644 --- a/projects/com.oracle.truffle.llvm.libraries.bitcode/include/polyglot.h +++ b/projects/com.oracle.truffle.llvm.libraries.bitcode/include/polyglot.h @@ -87,6 +87,19 @@ void polyglot_export(const char *name, void *value); */ void *polyglot_eval(const char *id, const char *code); +/** + * Evaluate a file containing source of another language. + * + * The filename argument can be absolute or relative to the current working + * directory. + * + * @param id the language identifier + * @param filename the file to be evaluated + * @return the result of the evaluation + * @see org::graalvm::polyglot::Context::eval + */ +void *polyglot_eval_file(const char *id, const char *filename); + /** * Access an argument of the current function. * diff --git a/projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/interop/LLVMPolyglotEval.java b/projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/interop/LLVMPolyglotEval.java index 3299063c0..38fbcda4b 100644 --- a/projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/interop/LLVMPolyglotEval.java +++ b/projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/interop/LLVMPolyglotEval.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. * * All rights reserved. * @@ -36,62 +36,100 @@ import com.oracle.truffle.api.dsl.NodeChild; import com.oracle.truffle.api.dsl.Specialization; import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMPolyglotEvalNodeGen.GetSourceFileNodeGen; +import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMPolyglotEvalNodeGen.GetSourceStringNodeGen; import com.oracle.truffle.llvm.nodes.intrinsics.llvm.LLVMIntrinsic; import com.oracle.truffle.llvm.runtime.LLVMContext; import com.oracle.truffle.llvm.runtime.interop.convert.ForeignToLLVM; import com.oracle.truffle.llvm.runtime.interop.convert.ForeignToLLVM.ForeignToLLVMType; import com.oracle.truffle.llvm.runtime.nodes.api.LLVMExpressionNode; +import com.oracle.truffle.llvm.runtime.nodes.api.LLVMNode; +import java.io.File; +import java.io.IOException; @NodeChild(type = LLVMExpressionNode.class) @NodeChild(type = LLVMExpressionNode.class) public abstract class LLVMPolyglotEval extends LLVMIntrinsic { - private final boolean legacyMimeTypeEval; - + @Child GetSourceNode getSource; @Child ForeignToLLVM toLLVM = ForeignToLLVM.create(ForeignToLLVMType.POINTER); public static LLVMPolyglotEval create(LLVMExpressionNode id, LLVMExpressionNode code) { - return LLVMPolyglotEvalNodeGen.create(false, id, code); + return LLVMPolyglotEvalNodeGen.create(GetSourceStringNodeGen.create(false), id, code); } - public static LLVMPolyglotEval createLegacy(LLVMExpressionNode mime, LLVMExpressionNode code) { - return LLVMPolyglotEvalNodeGen.create(true, mime, code); + public static LLVMPolyglotEval createFile(LLVMExpressionNode id, LLVMExpressionNode filename) { + return LLVMPolyglotEvalNodeGen.create(GetSourceFileNodeGen.create(), id, filename); } - protected LLVMPolyglotEval(boolean legacyMimeTypeEval) { - this.legacyMimeTypeEval = legacyMimeTypeEval; + public static LLVMPolyglotEval createLegacy(LLVMExpressionNode mime, LLVMExpressionNode code) { + return LLVMPolyglotEvalNodeGen.create(GetSourceStringNodeGen.create(true), mime, code); } - @TruffleBoundary - protected CallTarget getCallTarget(String id, String code, ContextReference context) { - Source sourceObject; - if (legacyMimeTypeEval) { - sourceObject = Source.newBuilder(code).name("").mimeType(id).build(); - } else { - sourceObject = Source.newBuilder(code).name("").language(id).build(); - } - return context.get().getEnv().parse(sourceObject); + LLVMPolyglotEval(GetSourceNode getSource) { + this.getSource = getSource; } - @SuppressWarnings("unused") - @Specialization(limit = "2", guards = {"id.equals(readId.executeWithTarget(idPointer))", "src.equals(readSrc.executeWithTarget(srcPointer))"}) - protected Object doCached(Object idPointer, Object srcPointer, + @Specialization + protected Object doEval(Object idPointer, Object srcPointer, @Cached("createReadString()") LLVMReadStringNode readId, - @Cached("createReadString()") LLVMReadStringNode readSrc, - @Cached("readId.executeWithTarget(idPointer)") String id, - @Cached("readSrc.executeWithTarget(srcPointer)") String src, - @Cached("getContextReference()") ContextReference context, - @Cached("getCallTarget(id, src, context)") CallTarget callTarget) { + @Cached("createReadString()") LLVMReadStringNode readSrc) { + CallTarget callTarget = getSource.execute(readId.executeWithTarget(idPointer), readSrc.executeWithTarget(srcPointer)); Object foreign = callTarget.call(); return toLLVM.executeWithTarget(foreign); } - @Specialization(replaces = "doCached") - protected Object uncached(Object idPointer, Object srcPointer, - @Cached("createReadString()") LLVMReadStringNode readId, - @Cached("createReadString()") LLVMReadStringNode readSrc, - @Cached("getContextReference()") ContextReference context) { - Object foreign = getCallTarget(readId.executeWithTarget(idPointer), readSrc.executeWithTarget(srcPointer), context).call(); - return toLLVM.executeWithTarget(foreign); + abstract static class GetSourceNode extends LLVMNode { + + abstract CallTarget execute(String languageId, String source); + } + + abstract static class GetSourceStringNode extends GetSourceNode { + + private final boolean legacyMimeTypeEval; + + protected GetSourceStringNode(boolean legacyMimeTypeEval) { + this.legacyMimeTypeEval = legacyMimeTypeEval; + } + + @SuppressWarnings("unused") + @Specialization(limit = "2", guards = {"id.equals(cachedId)", "code.equals(cachedCode)"}) + CallTarget doCached(String id, String code, + @Cached("id") String cachedId, + @Cached("code") String cachedCode, + @Cached("getContextReference()") ContextReference ctxRef, + @Cached("uncached(cachedId, cachedCode, ctxRef)") CallTarget callTarget) { + return callTarget; + } + + @TruffleBoundary + @Specialization(replaces = "doCached") + CallTarget uncached(String id, String code, + @Cached("getContextReference()") ContextReference ctxRef) { + Source sourceObject; + if (legacyMimeTypeEval) { + sourceObject = Source.newBuilder(code).name("").mimeType(id).build(); + } else { + sourceObject = Source.newBuilder(code).name("").language(id).build(); + } + return ctxRef.get().getEnv().parse(sourceObject); + } + } + + abstract static class GetSourceFileNode extends GetSourceNode { + + @TruffleBoundary + @Specialization + CallTarget uncached(String id, String filename, + @Cached("getContextReference()") ContextReference ctxRef) { + try { + // never cache, since the file content could change between invocations + Source sourceObject = Source.newBuilder(new File(filename)).name("").language(id).build(); + return ctxRef.get().getEnv().parse(sourceObject); + } catch (IOException ex) { + // TODO proper sulong exception + throw new IllegalStateException(ex); + } + } } } diff --git a/projects/com.oracle.truffle.llvm.parser.factories/src/com/oracle/truffle/llvm/parser/factories/NFIIntrinsicsProvider.java b/projects/com.oracle.truffle.llvm.parser.factories/src/com/oracle/truffle/llvm/parser/factories/NFIIntrinsicsProvider.java index 09a4a2ffa..efd4c089b 100644 --- a/projects/com.oracle.truffle.llvm.parser.factories/src/com/oracle/truffle/llvm/parser/factories/NFIIntrinsicsProvider.java +++ b/projects/com.oracle.truffle.llvm.parser.factories/src/com/oracle/truffle/llvm/parser/factories/NFIIntrinsicsProvider.java @@ -394,6 +394,13 @@ protected LLVMExpressionNode generate(FunctionType type) { } }); + factories.put("@polyglot_eval_file", new LLVMNativeIntrinsicFactory(true, true) { + @Override + protected LLVMExpressionNode generate(FunctionType type) { + return LLVMPolyglotEval.createFile(LLVMArgNodeGen.create(1), LLVMArgNodeGen.create(2)); + } + }); + // factories.put("@polyglot_is_value", new LLVMNativeIntrinsicFactory(true, true) { From 2c58976c320c0c7ebba57080608b1cef20974b64 Mon Sep 17 00:00:00 2001 From: Roland Schatz Date: Tue, 8 May 2018 11:09:50 +0200 Subject: [PATCH 4/8] New builtin polyglot_java_type. --- CHANGELOG.md | 2 +- .../include/polyglot.h | 8 +++ .../interop/LLVMPolyglotJavaType.java | 57 +++++++++++++++++++ .../factories/NFIIntrinsicsProvider.java | 8 +++ 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/interop/LLVMPolyglotJavaType.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c6ba58c8..5e4b04088 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ New features: * Use dynamic linker semantics when loading multiple bitcode files. * Support ELF files with embedded LLVM bitcode. -* New builtin polyglot_eval_file. +* New builtins `polyglot_eval_file` and `polyglot_java_type`. Improvements: diff --git a/projects/com.oracle.truffle.llvm.libraries.bitcode/include/polyglot.h b/projects/com.oracle.truffle.llvm.libraries.bitcode/include/polyglot.h index 51f3746a2..a2b2db8cc 100644 --- a/projects/com.oracle.truffle.llvm.libraries.bitcode/include/polyglot.h +++ b/projects/com.oracle.truffle.llvm.libraries.bitcode/include/polyglot.h @@ -100,6 +100,14 @@ void *polyglot_eval(const char *id, const char *code); */ void *polyglot_eval_file(const char *id, const char *filename); +/** + * Access a Java class via host interop. + * + * @param classname the name of the Java class + * @return the Java class, as polyglot value + */ +void *polyglot_java_type(const char *classname); + /** * Access an argument of the current function. * diff --git a/projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/interop/LLVMPolyglotJavaType.java b/projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/interop/LLVMPolyglotJavaType.java new file mode 100644 index 000000000..57d03ec3a --- /dev/null +++ b/projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/interop/LLVMPolyglotJavaType.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.oracle.truffle.llvm.nodes.intrinsics.interop; + +import com.oracle.truffle.api.TruffleLanguage.ContextReference; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.NodeChild; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.llvm.nodes.intrinsics.llvm.LLVMIntrinsic; +import com.oracle.truffle.llvm.runtime.LLVMContext; +import com.oracle.truffle.llvm.runtime.interop.convert.ForeignToLLVM; +import com.oracle.truffle.llvm.runtime.interop.convert.ForeignToLLVM.ForeignToLLVMType; +import com.oracle.truffle.llvm.runtime.nodes.api.LLVMExpressionNode; + +@NodeChild(value = "name", type = LLVMExpressionNode.class) +public abstract class LLVMPolyglotJavaType extends LLVMIntrinsic { + + @Child LLVMReadStringNode readString = LLVMReadStringNodeGen.create(); + @Child ForeignToLLVM toLLVM = ForeignToLLVM.create(ForeignToLLVMType.POINTER); + + @Specialization + protected Object doImport(Object name, + @Cached("getContextReference()") ContextReference ctxRef) { + String className = readString.executeWithTarget(name); + + LLVMContext ctx = ctxRef.get(); + Object ret = ctx.getEnv().lookupHostSymbol(className); + return toLLVM.executeWithTarget(ret); + } +} diff --git a/projects/com.oracle.truffle.llvm.parser.factories/src/com/oracle/truffle/llvm/parser/factories/NFIIntrinsicsProvider.java b/projects/com.oracle.truffle.llvm.parser.factories/src/com/oracle/truffle/llvm/parser/factories/NFIIntrinsicsProvider.java index efd4c089b..f9c24f927 100644 --- a/projects/com.oracle.truffle.llvm.parser.factories/src/com/oracle/truffle/llvm/parser/factories/NFIIntrinsicsProvider.java +++ b/projects/com.oracle.truffle.llvm.parser.factories/src/com/oracle/truffle/llvm/parser/factories/NFIIntrinsicsProvider.java @@ -100,6 +100,7 @@ import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMPolyglotGetStringSizeNodeGen; import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMPolyglotImportNodeGen; import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMPolyglotIsValueNodeGen; +import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMPolyglotJavaTypeNodeGen; import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMSulongFunctionToNativePointerNodeGen; import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMTruffleAddressToFunctionNodeGen; import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMTruffleBinaryFactory.LLVMTruffleHasKeysNodeGen; @@ -401,6 +402,13 @@ protected LLVMExpressionNode generate(FunctionType type) { } }); + factories.put("@polyglot_java_type", new LLVMNativeIntrinsicFactory(true, true) { + @Override + protected LLVMExpressionNode generate(FunctionType type) { + return LLVMPolyglotJavaTypeNodeGen.create(LLVMArgNodeGen.create(1)); + } + }); + // factories.put("@polyglot_is_value", new LLVMNativeIntrinsicFactory(true, true) { From 19bf318197c96b4d938d0e3dd26e7d343d1468a8 Mon Sep 17 00:00:00 2001 From: Roland Schatz Date: Tue, 8 May 2018 14:07:56 +0200 Subject: [PATCH 5/8] New builtins polyglot_remove_member and polyglot_remove_array_element. --- CHANGELOG.md | 8 +- .../include/polyglot.h | 18 ++++ .../interop/LLVMPolyglotRemove.java | 102 ++++++++++++++++++ .../factories/NFIIntrinsicsProvider.java | 18 ++++ 4 files changed, 145 insertions(+), 1 deletion(-) create mode 100644 projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/interop/LLVMPolyglotRemove.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e4b04088..9b642cabd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,13 @@ New features: * Use dynamic linker semantics when loading multiple bitcode files. * Support ELF files with embedded LLVM bitcode. -* New builtins `polyglot_eval_file` and `polyglot_java_type`. + +New polyglot builtins: + +* `polyglot_eval_file` +* `polyglot_java_type` +* `polyglot_remove_member` +* `polyglot_remove_array_element` Improvements: diff --git a/projects/com.oracle.truffle.llvm.libraries.bitcode/include/polyglot.h b/projects/com.oracle.truffle.llvm.libraries.bitcode/include/polyglot.h index a2b2db8cc..bb67c503f 100644 --- a/projects/com.oracle.truffle.llvm.libraries.bitcode/include/polyglot.h +++ b/projects/com.oracle.truffle.llvm.libraries.bitcode/include/polyglot.h @@ -361,6 +361,15 @@ void *polyglot_get_member(const void *object, const char *name); */ void polyglot_put_member(void *object, const char *name, ...); +/** + * Remove a named member from a polyglot object. + * + * @param object the polyglot value to modify + * @param name the name of the member to be removed + * @return true if the member was successfully removed, false otherwise + */ +bool polyglot_remove_member(void *object, const char *name); + /** * Check whether a polyglot value has array elements. * @@ -399,6 +408,15 @@ void *polyglot_get_array_element(const void *array, int idx); */ void polyglot_set_array_element(void *array, int idx, ...); +/** + * Remove an array element from a polyglot array. + * + * @param array the polyglot array to modify + * @param idx the index of the removed array element + * @return true if the array element was successfully removed, false otherwise + */ +bool polyglot_remove_array_element(void *array, int idx); + /** @} */ /** diff --git a/projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/interop/LLVMPolyglotRemove.java b/projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/interop/LLVMPolyglotRemove.java new file mode 100644 index 000000000..9a8ba0da4 --- /dev/null +++ b/projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/interop/LLVMPolyglotRemove.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.oracle.truffle.llvm.nodes.intrinsics.interop; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.NodeChild; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.ForeignAccess; +import com.oracle.truffle.api.interop.InteropException; +import com.oracle.truffle.api.interop.Message; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.llvm.nodes.intrinsics.llvm.LLVMIntrinsic; +import com.oracle.truffle.llvm.runtime.interop.LLVMAsForeignNode; +import com.oracle.truffle.llvm.runtime.nodes.api.LLVMExpressionNode; +import com.oracle.truffle.llvm.runtime.pointer.LLVMManagedPointer; + +public final class LLVMPolyglotRemove { + + @NodeChild(type = LLVMExpressionNode.class) + @NodeChild(type = LLVMExpressionNode.class) + public abstract static class LLVMPolyglotRemoveMember extends LLVMIntrinsic { + + @Child private Node foreignRemove = Message.REMOVE.createNode(); + @Child private LLVMAsForeignNode asForeign = LLVMAsForeignNode.create(); + + @Specialization + protected boolean doRemove(LLVMManagedPointer value, Object id, + @Cached("createReadString()") LLVMReadStringNode readStr) { + TruffleObject foreign = asForeign.execute(value); + try { + return ForeignAccess.sendRemove(foreignRemove, foreign, readStr.executeWithTarget(id)); + } catch (InteropException ex) { + CompilerDirectives.transferToInterpreter(); + throw ex.raise(); + } + } + + @Fallback + @TruffleBoundary + @SuppressWarnings("unused") + public boolean error(Object value, Object id) { + throw new IllegalArgumentException("Non-polyglot value passed to polyglot_remove_member."); + } + } + + @NodeChild(type = LLVMExpressionNode.class) + @NodeChild(type = LLVMExpressionNode.class) + public abstract static class LLVMPolyglotRemoveArrayElement extends LLVMIntrinsic { + + @Child private Node foreignRemove = Message.REMOVE.createNode(); + @Child private LLVMAsForeignNode asForeign = LLVMAsForeignNode.create(); + + @Specialization + protected boolean doRemove(LLVMManagedPointer value, int idx) { + TruffleObject foreign = asForeign.execute(value); + try { + return ForeignAccess.sendRemove(foreignRemove, foreign, idx); + } catch (InteropException ex) { + CompilerDirectives.transferToInterpreter(); + throw ex.raise(); + } + } + + @Fallback + @TruffleBoundary + @SuppressWarnings("unused") + public boolean fallback(Object value, Object id) { + throw new IllegalArgumentException("Non-polyglot value passed to polyglot_remove_array_element."); + } + } +} diff --git a/projects/com.oracle.truffle.llvm.parser.factories/src/com/oracle/truffle/llvm/parser/factories/NFIIntrinsicsProvider.java b/projects/com.oracle.truffle.llvm.parser.factories/src/com/oracle/truffle/llvm/parser/factories/NFIIntrinsicsProvider.java index f9c24f927..acb7b35fa 100644 --- a/projects/com.oracle.truffle.llvm.parser.factories/src/com/oracle/truffle/llvm/parser/factories/NFIIntrinsicsProvider.java +++ b/projects/com.oracle.truffle.llvm.parser.factories/src/com/oracle/truffle/llvm/parser/factories/NFIIntrinsicsProvider.java @@ -101,6 +101,8 @@ import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMPolyglotImportNodeGen; import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMPolyglotIsValueNodeGen; import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMPolyglotJavaTypeNodeGen; +import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMPolyglotRemoveFactory.LLVMPolyglotRemoveArrayElementNodeGen; +import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMPolyglotRemoveFactory.LLVMPolyglotRemoveMemberNodeGen; import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMSulongFunctionToNativePointerNodeGen; import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMTruffleAddressToFunctionNodeGen; import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMTruffleBinaryFactory.LLVMTruffleHasKeysNodeGen; @@ -680,6 +682,22 @@ protected LLVMExpressionNode generate(FunctionType type) { } }); + factories.put("@polyglot_remove_member", new LLVMNativeIntrinsicFactory(true, true) { + + @Override + protected LLVMExpressionNode generate(FunctionType type) { + return LLVMPolyglotRemoveMemberNodeGen.create(LLVMArgNodeGen.create(1), LLVMArgNodeGen.create(2)); + } + }); + + factories.put("@polyglot_remove_array_element", new LLVMNativeIntrinsicFactory(true, true) { + + @Override + protected LLVMExpressionNode generate(FunctionType type) { + return LLVMPolyglotRemoveArrayElementNodeGen.create(LLVMArgNodeGen.create(1), LLVMArgNodeGen.create(2)); + } + }); + LLVMNativeIntrinsicFactory polyglotAsI8 = new LLVMNativeIntrinsicFactory(true, true) { @Override From ed15374a31e4bb6464ee25b53466e0bd25b390a5 Mon Sep 17 00:00:00 2001 From: Roland Schatz Date: Tue, 8 May 2018 14:42:48 +0200 Subject: [PATCH 6/8] New builtins polyglot_can_instantiate and polyglot_new_instance. --- CHANGELOG.md | 2 + .../include/polyglot.h | 17 +++ .../interop/LLVMPolyglotNewInstance.java | 121 ++++++++++++++++++ .../interop/LLVMPolyglotPredicate.java | 63 +++++++++ .../factories/NFIIntrinsicsProvider.java | 18 +++ 5 files changed, 221 insertions(+) create mode 100644 projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/interop/LLVMPolyglotNewInstance.java create mode 100644 projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/interop/LLVMPolyglotPredicate.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b642cabd..24f5651d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ New polyglot builtins: * `polyglot_java_type` * `polyglot_remove_member` * `polyglot_remove_array_element` +* `polyglot_can_instantiate` +* `polyglot_new_instance` Improvements: diff --git a/projects/com.oracle.truffle.llvm.libraries.bitcode/include/polyglot.h b/projects/com.oracle.truffle.llvm.libraries.bitcode/include/polyglot.h index bb67c503f..efc686469 100644 --- a/projects/com.oracle.truffle.llvm.libraries.bitcode/include/polyglot.h +++ b/projects/com.oracle.truffle.llvm.libraries.bitcode/include/polyglot.h @@ -317,6 +317,23 @@ bool polyglot_can_execute(const void *value); */ void *polyglot_invoke(void *object, const char *name, ...); +/** + * Check whether a polyglot value can be instantiated. + * + * Returns false for pointers that do not point to a polyglot value (see + * {@link polyglot_is_value}). + */ +bool polyglot_can_instantiate(const void *object); + +/** + * Instantiate a polyglot value. + * + * @param object the polyglot value that should be instantiated + * @param ... the arguments of the constructor + * @return the new object, as polyglot value + */ +void *polyglot_new_instance(const void *object, ...); + /** @} */ /** diff --git a/projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/interop/LLVMPolyglotNewInstance.java b/projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/interop/LLVMPolyglotNewInstance.java new file mode 100644 index 000000000..f3677b298 --- /dev/null +++ b/projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/interop/LLVMPolyglotNewInstance.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.oracle.truffle.llvm.nodes.intrinsics.interop; + +import com.oracle.truffle.llvm.runtime.interop.LLVMAsForeignNode; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; +import com.oracle.truffle.api.TruffleLanguage.ContextReference; +import com.oracle.truffle.api.dsl.Cached; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.NodeChild; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.frame.VirtualFrame; +import com.oracle.truffle.api.interop.ArityException; +import com.oracle.truffle.api.interop.ForeignAccess; +import com.oracle.truffle.api.interop.Message; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.interop.UnsupportedMessageException; +import com.oracle.truffle.api.interop.UnsupportedTypeException; +import com.oracle.truffle.api.nodes.ExplodeLoop; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.llvm.nodes.intrinsics.llvm.LLVMIntrinsic; +import com.oracle.truffle.llvm.runtime.LLVMContext; +import com.oracle.truffle.llvm.runtime.LLVMGetStackNode; +import com.oracle.truffle.llvm.runtime.interop.LLVMDataEscapeNode; +import com.oracle.truffle.llvm.runtime.interop.convert.ForeignToLLVM; +import com.oracle.truffle.llvm.runtime.interop.convert.ForeignToLLVM.ForeignToLLVMType; +import com.oracle.truffle.llvm.runtime.memory.LLVMStack; +import com.oracle.truffle.llvm.runtime.memory.LLVMStack.StackPointer; +import com.oracle.truffle.llvm.runtime.memory.LLVMThreadingStack; +import com.oracle.truffle.llvm.runtime.nodes.api.LLVMExpressionNode; +import com.oracle.truffle.llvm.runtime.pointer.LLVMManagedPointer; + +@NodeChild(value = "object", type = LLVMExpressionNode.class) +public abstract class LLVMPolyglotNewInstance extends LLVMIntrinsic { + + @Children private final LLVMExpressionNode[] args; + @Children private final LLVMDataEscapeNode[] prepareValuesForEscape; + + @Child private Node foreignNewInstance; + @Child private ForeignToLLVM toLLVM = ForeignToLLVM.create(ForeignToLLVMType.POINTER); + @Child private LLVMAsForeignNode asForeign = LLVMAsForeignNode.create(); + + public LLVMPolyglotNewInstance(LLVMExpressionNode[] args) { + this.args = args; + this.prepareValuesForEscape = new LLVMDataEscapeNode[args.length]; + for (int i = 0; i < prepareValuesForEscape.length; i++) { + prepareValuesForEscape[i] = LLVMDataEscapeNode.create(); + } + this.foreignNewInstance = Message.createNew(args.length).createNode(); + } + + @CompilationFinal private LLVMThreadingStack threadingStack = null; + + private LLVMThreadingStack getThreadingStack(LLVMContext context) { + if (threadingStack == null) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + threadingStack = context.getThreadingStack(); + } + return threadingStack; + } + + @Specialization + @ExplodeLoop + protected Object doNew(VirtualFrame frame, LLVMManagedPointer value, + @Cached("getContextReference()") ContextReference ctxRef, + @Cached("create()") LLVMGetStackNode getStack) { + TruffleObject foreign = asForeign.execute(value); + + Object[] evaluatedArgs = new Object[args.length]; + for (int i = 0; i < args.length; i++) { + evaluatedArgs[i] = prepareValuesForEscape[i].executeWithTarget(args[i].executeGeneric(frame)); + } + + LLVMStack stack = getStack.executeWithTarget(getThreadingStack(ctxRef.get()), Thread.currentThread()); + try { + Object rawValue; + try (StackPointer save = stack.newFrame()) { + rawValue = ForeignAccess.sendNew(foreignNewInstance, foreign, evaluatedArgs); + } + return toLLVM.executeWithTarget(rawValue); + } catch (UnsupportedMessageException | UnsupportedTypeException | ArityException e) { + CompilerDirectives.transferToInterpreter(); + throw e.raise(); + } + } + + @Fallback + @SuppressWarnings("unused") + public Object fallback(Object value) { + CompilerDirectives.transferToInterpreter(); + throw new IllegalArgumentException("Non-polyglot value passed to polyglot_new_instance."); + } +} diff --git a/projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/interop/LLVMPolyglotPredicate.java b/projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/interop/LLVMPolyglotPredicate.java new file mode 100644 index 000000000..771845505 --- /dev/null +++ b/projects/com.oracle.truffle.llvm.nodes/src/com/oracle/truffle/llvm/nodes/intrinsics/interop/LLVMPolyglotPredicate.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.oracle.truffle.llvm.nodes.intrinsics.interop; + +import com.oracle.truffle.llvm.runtime.interop.LLVMAsForeignNode; +import com.oracle.truffle.api.dsl.Fallback; +import com.oracle.truffle.api.dsl.NodeChild; +import com.oracle.truffle.api.dsl.Specialization; +import com.oracle.truffle.api.interop.ForeignAccess; +import com.oracle.truffle.api.interop.Message; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.llvm.nodes.intrinsics.llvm.LLVMIntrinsic; +import com.oracle.truffle.llvm.runtime.nodes.api.LLVMExpressionNode; +import com.oracle.truffle.llvm.runtime.pointer.LLVMManagedPointer; + +public abstract class LLVMPolyglotPredicate extends LLVMIntrinsic { + + @NodeChild(type = LLVMExpressionNode.class) + public abstract static class LLVMPolyglotCanInstantiate extends LLVMIntrinsic { + + @Child private LLVMAsForeignNode asForeign = LLVMAsForeignNode.createOptional(); + @Child private Node foreignIsInstantiable = Message.IS_INSTANTIABLE.createNode(); + + @Specialization + protected boolean doIntrinsic(LLVMManagedPointer value) { + TruffleObject foreign = asForeign.execute(value); + return foreign != null && ForeignAccess.sendIsInstantiable(foreignIsInstantiable, foreign); + } + + @Fallback + public Object fallback(@SuppressWarnings("unused") Object value) { + return false; + } + } +} diff --git a/projects/com.oracle.truffle.llvm.parser.factories/src/com/oracle/truffle/llvm/parser/factories/NFIIntrinsicsProvider.java b/projects/com.oracle.truffle.llvm.parser.factories/src/com/oracle/truffle/llvm/parser/factories/NFIIntrinsicsProvider.java index acb7b35fa..26740c768 100644 --- a/projects/com.oracle.truffle.llvm.parser.factories/src/com/oracle/truffle/llvm/parser/factories/NFIIntrinsicsProvider.java +++ b/projects/com.oracle.truffle.llvm.parser.factories/src/com/oracle/truffle/llvm/parser/factories/NFIIntrinsicsProvider.java @@ -101,6 +101,8 @@ import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMPolyglotImportNodeGen; import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMPolyglotIsValueNodeGen; import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMPolyglotJavaTypeNodeGen; +import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMPolyglotNewInstanceNodeGen; +import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMPolyglotPredicateFactory.LLVMPolyglotCanInstantiateNodeGen; import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMPolyglotRemoveFactory.LLVMPolyglotRemoveArrayElementNodeGen; import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMPolyglotRemoveFactory.LLVMPolyglotRemoveMemberNodeGen; import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMSulongFunctionToNativePointerNodeGen; @@ -769,6 +771,14 @@ protected LLVMExpressionNode generate(FunctionType type) { // + factories.put("@polyglot_new_instance", new LLVMNativeIntrinsicFactory(true, true) { + + @Override + protected LLVMExpressionNode generate(FunctionType type) { + return LLVMPolyglotNewInstanceNodeGen.create(argumentsArray(2, type.getArgumentTypes().length - 2), LLVMArgNodeGen.create(1)); + } + }); + LLVMNativeIntrinsicFactory polyglotInvoke = new LLVMNativeIntrinsicFactory(true, true) { @Override @@ -912,6 +922,14 @@ protected LLVMExpressionNode generate(FunctionType type) { factories.put("@polyglot_can_execute", polyglotCanExecute); factories.put("@truffle_is_executable", polyglotCanExecute); + factories.put("@polyglot_can_instantiate", new LLVMNativeIntrinsicFactory(true, true) { + + @Override + protected LLVMExpressionNode generate(FunctionType type) { + return LLVMPolyglotCanInstantiateNodeGen.create(LLVMArgNodeGen.create(1)); + } + }); + LLVMNativeIntrinsicFactory polyglotIsNull = new LLVMNativeIntrinsicFactory(true, true) { @Override From 878998131e6f53f2af53630189dceba7449ef65d Mon Sep 17 00:00:00 2001 From: Roland Schatz Date: Tue, 8 May 2018 16:43:29 +0200 Subject: [PATCH 7/8] Unit tests for new polyglot builtins. --- .../test/interop/PolyglotBuiltinTest.java | 130 ++++++++++++++++++ .../llvm/test/interop/TypeCheckTest.java | 3 + .../llvm/test/interop/values/ArrayObject.java | 9 ++ .../test/interop/values/BoxedTestValue.java | 4 + .../test/interop/values/StructObject.java | 15 +- .../test/interop/values/TestCallback.java | 2 +- .../test/interop/values/TestConstructor.java | 79 +++++++++++ .../interop/polyglotBuiltinTest.c | 17 +++ .../interop/typeCheck.c | 3 + 9 files changed, 260 insertions(+), 2 deletions(-) create mode 100644 projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/PolyglotBuiltinTest.java create mode 100644 projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/values/TestConstructor.java create mode 100644 tests/com.oracle.truffle.llvm.tests.interop/interop/polyglotBuiltinTest.c diff --git a/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/PolyglotBuiltinTest.java b/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/PolyglotBuiltinTest.java new file mode 100644 index 000000000..e62e8d5ec --- /dev/null +++ b/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/PolyglotBuiltinTest.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.oracle.truffle.llvm.test.interop; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import com.oracle.truffle.api.CallTarget; +import com.oracle.truffle.api.TruffleOptions; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.llvm.test.interop.values.ArrayObject; +import com.oracle.truffle.llvm.test.interop.values.BoxedTestValue; +import com.oracle.truffle.llvm.test.interop.values.NullValue; +import com.oracle.truffle.llvm.test.interop.values.StructObject; +import com.oracle.truffle.llvm.test.interop.values.TestConstructor; +import com.oracle.truffle.tck.TruffleRunner; +import com.oracle.truffle.tck.TruffleRunner.Inject; +import java.math.BigInteger; +import java.util.HashMap; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import org.junit.Assume; + +@RunWith(TruffleRunner.class) +public class PolyglotBuiltinTest extends InteropTestBase { + + private static TruffleObject testLibrary; + + @BeforeClass + public static void loadTestBitcode() { + testLibrary = InteropTestBase.loadTestBitcodeInternal("polyglotBuiltinTest"); + } + + public static class TestNewNode extends SulongTestNode { + + public TestNewNode() { + super(testLibrary, "test_new", 1); + } + } + + @Test + public void testNew(@Inject(TestNewNode.class) CallTarget testNew) { + Object ret = testNew.call(new TestConstructor(1, args -> new BoxedTestValue(args[0]))); + + Assert.assertThat(ret, is(instanceOf(BoxedTestValue.class))); + BoxedTestValue value = (BoxedTestValue) ret; + Assert.assertEquals(42, value.getValue()); + } + + public static class TestRemoveMemberNode extends SulongTestNode { + + public TestRemoveMemberNode() { + super(testLibrary, "test_remove_member", 1); + } + } + + @Test + public void testRemoveMember(@Inject(TestRemoveMemberNode.class) CallTarget testRemoveMember) { + HashMap map = new HashMap<>(); + map.put("test", new NullValue()); + + Object ret = testRemoveMember.call(new StructObject(map)); + Assert.assertEquals("ret", true, ret); + + Assert.assertFalse("containsKey(test)", map.containsKey("test")); + } + + public static class TestRemoveArrayElementNode extends SulongTestNode { + + public TestRemoveArrayElementNode() { + super(testLibrary, "test_remove_array_element", 1); + } + } + + @Test + public void testRemoveIndex(@Inject(TestRemoveArrayElementNode.class) CallTarget testRemoveArrayElement) { + Object[] arr = new Object[5]; + + Object ret = testRemoveArrayElement.call(new ArrayObject(arr)); + Assert.assertEquals("ret", true, ret); + + Assert.assertEquals("arr[3]", "", arr[3]); + } + + public static class TestHostInteropNode extends SulongTestNode { + + public TestHostInteropNode() { + super(testLibrary, "test_host_interop", 0); + } + } + + @Test + public void testHostInterop(@Inject(TestHostInteropNode.class) CallTarget testHostInterop) { + Assume.assumeFalse("skipping host interop test in native mode", TruffleOptions.AOT); + + Object ret = testHostInterop.call(); + + Assert.assertTrue("isHostObject", runWithPolyglot.getTruffleTestEnv().isHostObject(ret)); + Assert.assertSame("ret", BigInteger.class, runWithPolyglot.getTruffleTestEnv().asHostObject(ret)); + } +} diff --git a/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/TypeCheckTest.java b/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/TypeCheckTest.java index e5c8f0e05..1a2a6958a 100644 --- a/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/TypeCheckTest.java +++ b/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/TypeCheckTest.java @@ -30,6 +30,7 @@ package com.oracle.truffle.llvm.test.interop; import com.oracle.truffle.llvm.test.interop.values.BoxedTestValue; +import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -82,6 +83,7 @@ public Object execute(Value... arguments) { return null; } }}); + tests.add(new Object[]{"class", BigInteger.class}); return tests; } @@ -101,5 +103,6 @@ public void checkTypes() { Assert.assertEquals("can_execute", v.canExecute(), (ret & 32) != 0); Assert.assertEquals("has_array_elements", v.hasArrayElements(), (ret & 64) != 0); Assert.assertEquals("has_members", v.hasMembers(), (ret & 128) != 0); + Assert.assertEquals("can_instantiate", v.canInstantiate(), (ret & 256) != 0); } } diff --git a/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/values/ArrayObject.java b/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/values/ArrayObject.java index 2aeae5b70..16665d669 100644 --- a/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/values/ArrayObject.java +++ b/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/values/ArrayObject.java @@ -68,6 +68,15 @@ Object access(ArrayObject obj, Number idx, Object value) { } } + @Resolve(message = "REMOVE") + abstract static class RemoveNode extends Node { + + boolean access(ArrayObject obj, Number idx) { + obj.array[(int) idx.longValue()] = ""; + return true; + } + } + @Resolve(message = "GET_SIZE") abstract static class SizeNode extends Node { diff --git a/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/values/BoxedTestValue.java b/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/values/BoxedTestValue.java index 8744518a4..f224f1665 100644 --- a/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/values/BoxedTestValue.java +++ b/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/values/BoxedTestValue.java @@ -45,6 +45,10 @@ public BoxedTestValue(Object value) { this.value = value; } + public Object getValue() { + return value; + } + @Override public ForeignAccess getForeignAccess() { return ForeignAccess.create(BoxedTestValue.class, new StandardFactory() { diff --git a/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/values/StructObject.java b/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/values/StructObject.java index 766d7fca5..3888383dc 100644 --- a/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/values/StructObject.java +++ b/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/values/StructObject.java @@ -82,6 +82,19 @@ Object access(StructObject obj, String name, Object value) { } } + @Resolve(message = "REMOVE") + abstract static class RemoveNode extends Node { + + @CompilerDirectives.TruffleBoundary + boolean access(StructObject obj, String name) { + if (!obj.properties.containsKey(name)) { + throw UnknownIdentifierException.raise(name); + } + obj.properties.remove(name); + return true; + } + } + @Resolve(message = "KEYS") abstract static class KeysNode extends Node { @@ -99,7 +112,7 @@ int access(StructObject obj, String name) { if (!obj.properties.containsKey(name)) { return KeyInfo.NONE; } - return KeyInfo.READABLE | KeyInfo.MODIFIABLE; + return KeyInfo.READABLE | KeyInfo.MODIFIABLE | KeyInfo.REMOVABLE; } } diff --git a/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/values/TestCallback.java b/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/values/TestCallback.java index 8c150fca8..2f05f6884 100644 --- a/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/values/TestCallback.java +++ b/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/values/TestCallback.java @@ -64,7 +64,7 @@ Object call(Object... args) { } static boolean isInstance(TruffleObject object) { - return object instanceof ArrayObject; + return object instanceof TestCallback; } @Override diff --git a/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/values/TestConstructor.java b/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/values/TestConstructor.java new file mode 100644 index 000000000..bf5fb7ae1 --- /dev/null +++ b/projects/com.oracle.truffle.llvm.test/src/com/oracle/truffle/llvm/test/interop/values/TestConstructor.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.oracle.truffle.llvm.test.interop.values; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.interop.ArityException; +import com.oracle.truffle.api.interop.ForeignAccess; +import com.oracle.truffle.api.interop.MessageResolution; +import com.oracle.truffle.api.interop.Resolve; +import com.oracle.truffle.api.interop.TruffleObject; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.llvm.test.interop.values.TestCallback.Function; + +@MessageResolution(receiverType = TestConstructor.class) +public class TestConstructor implements TruffleObject { + + private final int arity; + private final Function constructor; + + public TestConstructor(int arity, Function constructor) { + this.arity = arity; + this.constructor = constructor; + } + + @TruffleBoundary + Object call(Object... args) { + if (args.length == arity) { + Object ret = constructor.call(args); + return ret; + } else { + throw ArityException.raise(arity, args.length); + } + } + + static boolean isInstance(TruffleObject object) { + return object instanceof TestConstructor; + } + + @Override + public ForeignAccess getForeignAccess() { + return TestConstructorForeign.ACCESS; + } + + @Resolve(message = "NEW") + abstract static class NewNode extends Node { + + Object access(TestConstructor constructor, Object[] arguments) { + Object res = constructor.call(arguments); + return res == null ? new NullValue() : res; + } + } +} diff --git a/tests/com.oracle.truffle.llvm.tests.interop/interop/polyglotBuiltinTest.c b/tests/com.oracle.truffle.llvm.tests.interop/interop/polyglotBuiltinTest.c new file mode 100644 index 000000000..5d7c46556 --- /dev/null +++ b/tests/com.oracle.truffle.llvm.tests.interop/interop/polyglotBuiltinTest.c @@ -0,0 +1,17 @@ +#include + +void *test_new(void *constructor) { + return polyglot_new_instance(constructor, 42); +} + +bool test_remove_member(void *object) { + return polyglot_remove_member(object, "test"); +} + +bool test_remove_array_element(void *array) { + return polyglot_remove_array_element(array, 3); +} + +void *test_host_interop() { + return polyglot_java_type("java.math.BigInteger"); +} diff --git a/tests/com.oracle.truffle.llvm.tests.interop/interop/typeCheck.c b/tests/com.oracle.truffle.llvm.tests.interop/interop/typeCheck.c index 4d88e3c59..ee34a03de 100644 --- a/tests/com.oracle.truffle.llvm.tests.interop/interop/typeCheck.c +++ b/tests/com.oracle.truffle.llvm.tests.interop/interop/typeCheck.c @@ -26,6 +26,9 @@ int check_types(void *value) { if (polyglot_has_members(value)) { ret |= 128; } + if (polyglot_can_instantiate(value)) { + ret |= 256; + } return ret; } From 5b494e709b1007c42cf0f060b904000cf72d1272 Mon Sep 17 00:00:00 2001 From: Roland Schatz Date: Wed, 9 May 2018 11:56:54 +0200 Subject: [PATCH 8/8] Improve CHANGELOG message. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 24f5651d9..4c3f54851 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ New polyglot builtins: Improvements: -* Unified representation of pointers to native memory and polyglot values. +* Support polyglot values in all pointer operations. # Version 1.0.0 RC1