diff --git a/CHANGELOG.md b/CHANGELOG.md index f7d5fc4a5..4c3f54851 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,18 @@ New features: * Use dynamic linker semantics when loading multiple bitcode files. * Support ELF files with embedded LLVM bitcode. +New polyglot builtins: + +* `polyglot_eval_file` +* `polyglot_java_type` +* `polyglot_remove_member` +* `polyglot_remove_array_element` +* `polyglot_can_instantiate` +* `polyglot_new_instance` + Improvements: -* Unified representation of pointers to native memory and polyglot values. +* Support polyglot values in all pointer operations. # Version 1.0.0 RC1 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..efc686469 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,27 @@ 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 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. * @@ -296,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, ...); + /** @} */ /** @@ -340,6 +378,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. * @@ -378,6 +425,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/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.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.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.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.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; } } diff --git a/projects/com.oracle.truffle.llvm.parser.factories/src/com/oracle/truffle/llvm/parser/factories/BasicIntrinsicsProvider.java b/projects/com.oracle.truffle.llvm.parser.factories/src/com/oracle/truffle/llvm/parser/factories/BasicIntrinsicsProvider.java index 54d572462..548752728 100644 --- a/projects/com.oracle.truffle.llvm.parser.factories/src/com/oracle/truffle/llvm/parser/factories/BasicIntrinsicsProvider.java +++ b/projects/com.oracle.truffle.llvm.parser.factories/src/com/oracle/truffle/llvm/parser/factories/BasicIntrinsicsProvider.java @@ -100,6 +100,11 @@ 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.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; import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMTruffleAddressToFunctionNodeGen; import com.oracle.truffle.llvm.nodes.intrinsics.interop.LLVMTruffleBinaryFactory.LLVMTruffleHasKeysNodeGen; @@ -399,6 +404,20 @@ 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_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) { @@ -670,6 +689,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 @@ -741,6 +776,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 @@ -884,6 +927,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 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.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/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 11e9abdea..376fe752b 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 @@ -218,6 +218,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 { 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; }