Skip to content
This repository has been archived by the owner on Aug 22, 2019. It is now read-only.

Commit

Permalink
[GR-8191] [GR-9455] [GR-9623] New polyglot builtins.
Browse files Browse the repository at this point in the history
PullRequest: sulong/535
  • Loading branch information
rschatz committed May 9, 2018
2 parents f2ab9fe + 5b494e7 commit a8ec4a7
Show file tree
Hide file tree
Showing 20 changed files with 815 additions and 45 deletions.
11 changes: 10 additions & 1 deletion CHANGELOG.md
Expand Up @@ -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

Expand Down
Expand Up @@ -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.
*
Expand Down Expand Up @@ -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, ...);

/** @} */

/**
Expand Down Expand Up @@ -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.
*
Expand Down Expand Up @@ -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);

/** @} */

/**
Expand Down
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates.
* Copyright (c) 2016, 2018, Oracle and/or its affiliates.
*
* All rights reserved.
*
Expand Down Expand Up @@ -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<LLVMContext> context) {
Source sourceObject;
if (legacyMimeTypeEval) {
sourceObject = Source.newBuilder(code).name("<eval>").mimeType(id).build();
} else {
sourceObject = Source.newBuilder(code).name("<eval>").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<LLVMContext> 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<LLVMContext> 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<LLVMContext> ctxRef,
@Cached("uncached(cachedId, cachedCode, ctxRef)") CallTarget callTarget) {
return callTarget;
}

@TruffleBoundary
@Specialization(replaces = "doCached")
CallTarget uncached(String id, String code,
@Cached("getContextReference()") ContextReference<LLVMContext> ctxRef) {
Source sourceObject;
if (legacyMimeTypeEval) {
sourceObject = Source.newBuilder(code).name("<eval>").mimeType(id).build();
} else {
sourceObject = Source.newBuilder(code).name("<eval>").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<LLVMContext> ctxRef) {
try {
// never cache, since the file content could change between invocations
Source sourceObject = Source.newBuilder(new File(filename)).name("<eval>").language(id).build();
return ctxRef.get().getEnv().parse(sourceObject);
} catch (IOException ex) {
// TODO proper sulong exception
throw new IllegalStateException(ex);
}
}
}
}
@@ -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<LLVMContext> ctxRef) {
String className = readString.executeWithTarget(name);

LLVMContext ctx = ctxRef.get();
Object ret = ctx.getEnv().lookupHostSymbol(className);
return toLLVM.executeWithTarget(ret);
}
}

0 comments on commit a8ec4a7

Please sign in to comment.