-
Notifications
You must be signed in to change notification settings - Fork 323
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
45 changed files
with
1,393 additions
and
220 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
67 changes: 67 additions & 0 deletions
67
engine/runtime/src/main/java/org/enso/interpreter/epb/EpbContext.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package org.enso.interpreter.epb; | ||
|
||
import com.oracle.truffle.api.CompilerDirectives; | ||
import com.oracle.truffle.api.TruffleLanguage; | ||
import org.enso.interpreter.epb.runtime.GuardedTruffleContext; | ||
|
||
/** | ||
* A context for {@link EpbLanguage}. Provides access to both isolated Truffle contexts used in | ||
* polyglot execution. | ||
*/ | ||
public class EpbContext { | ||
private static final String INNER_OPTION = "isEpbInner"; | ||
private final boolean isInner; | ||
private final TruffleLanguage.Env env; | ||
private @CompilerDirectives.CompilationFinal GuardedTruffleContext innerContext; | ||
private final GuardedTruffleContext currentContext; | ||
|
||
/** | ||
* Creates a new instance of this context. | ||
* | ||
* @param env the current language environment. | ||
*/ | ||
public EpbContext(TruffleLanguage.Env env) { | ||
this.env = env; | ||
isInner = env.getConfig().get(INNER_OPTION) != null; | ||
currentContext = new GuardedTruffleContext(env.getContext(), isInner); | ||
} | ||
|
||
/** | ||
* Initializes the context. No-op in the inner context. Spawns the inner context if called from | ||
* the outer context. | ||
*/ | ||
public void initialize() { | ||
if (!isInner) { | ||
innerContext = | ||
new GuardedTruffleContext( | ||
env.newContextBuilder().config(INNER_OPTION, "yes").build(), true); | ||
} | ||
} | ||
|
||
/** | ||
* Checks if this context corresponds to the inner Truffle context. | ||
* | ||
* @return true if run in the inner Truffle context, false otherwise. | ||
*/ | ||
public boolean isInner() { | ||
return isInner; | ||
} | ||
|
||
/** | ||
* @return the inner Truffle context handle if called from the outer context, or null if called in | ||
* the inner context. | ||
*/ | ||
public GuardedTruffleContext getInnerContext() { | ||
return innerContext; | ||
} | ||
|
||
/** @return returns the currently entered Truffle context handle. */ | ||
public GuardedTruffleContext getCurrentContext() { | ||
return currentContext; | ||
} | ||
|
||
/** @return the language environment associated with this context. */ | ||
public TruffleLanguage.Env getEnv() { | ||
return env; | ||
} | ||
} |
65 changes: 65 additions & 0 deletions
65
engine/runtime/src/main/java/org/enso/interpreter/epb/EpbLanguage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package org.enso.interpreter.epb; | ||
|
||
import com.oracle.truffle.api.CallTarget; | ||
import com.oracle.truffle.api.Truffle; | ||
import com.oracle.truffle.api.TruffleLanguage; | ||
import org.enso.interpreter.epb.node.ContextRewrapNode; | ||
import org.enso.interpreter.epb.node.ForeignEvalNode; | ||
|
||
/** | ||
* An internal language that serves as a bridge between Enso and other supported languages. | ||
* | ||
* <p>Truffle places a lot of emphasis on safety guarantees, which also means that single-threaded | ||
* languages cannot easily be called from multiple threads. We circumvent this by using two separate | ||
* {@link com.oracle.truffle.api.TruffleContext}s, one (often referred to as "outer") is allowed to | ||
* run Enso, Host Java, and possibly other thread-ready languages. Languages that cannot safely run | ||
* in a multithreaded environment are relegated to the other context (referred to as "inner"). The | ||
* inner context provides a GIL capability, ensuring that access to the single-threaded languages is | ||
* serialized. | ||
* | ||
* <p>This imposes certain limitations on data interchange between the contexts. In particular, it | ||
* is impossible to execute origin language's code when executing in the other context. Therefore | ||
* outer context values need to be specially wrapped before being passed (e.g. as arguments) to the | ||
* inner context, and inner context values need rewrapping for use in the outer context. See {@link | ||
* org.enso.interpreter.epb.runtime.PolyglotProxy} and {@link | ||
* ContextRewrapNode} for details of how and when this wrapping is done. | ||
* | ||
* <p>With the structure outlined above, EPB is the only language that is initialized in both inner | ||
* and outer contexts and thus it is very minimal. Its only role is to manage both contexts and | ||
* provide context-switching facilities. | ||
*/ | ||
@TruffleLanguage.Registration( | ||
id = EpbLanguage.ID, | ||
name = "Enso Polyglot Bridge", | ||
characterMimeTypes = {EpbLanguage.MIME}, | ||
// TODO mark this language as internal when https://github.com/oracle/graal/pull/3139 is | ||
// released | ||
internal = false, | ||
defaultMimeType = EpbLanguage.MIME, | ||
contextPolicy = TruffleLanguage.ContextPolicy.SHARED) | ||
public class EpbLanguage extends TruffleLanguage<EpbContext> { | ||
public static final String ID = "epb"; | ||
public static final String MIME = "application/epb"; | ||
|
||
@Override | ||
protected EpbContext createContext(Env env) { | ||
return new EpbContext(env); | ||
} | ||
|
||
@Override | ||
protected void initializeContext(EpbContext context) { | ||
context.initialize(); | ||
} | ||
|
||
@Override | ||
protected CallTarget parse(ParsingRequest request) { | ||
EpbParser.Result code = EpbParser.parse(request.getSource()); | ||
return Truffle.getRuntime() | ||
.createCallTarget(ForeignEvalNode.build(this, code, request.getArgumentNames())); | ||
} | ||
|
||
@Override | ||
protected boolean isThreadAccessAllowed(Thread thread, boolean singleThreaded) { | ||
return true; | ||
} | ||
} |
86 changes: 86 additions & 0 deletions
86
engine/runtime/src/main/java/org/enso/interpreter/epb/EpbParser.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package org.enso.interpreter.epb; | ||
|
||
import com.oracle.truffle.api.source.Source; | ||
|
||
import java.util.Arrays; | ||
|
||
/** A class containing helpers for creating and parsing EPB code */ | ||
public class EpbParser { | ||
private static final String separator = "#"; | ||
|
||
/** Lists all the languages supported in polyglot eval. */ | ||
public enum ForeignLanguage { | ||
JS("js", "js"); | ||
|
||
private final String truffleId; | ||
private final String syntacticTag; | ||
|
||
ForeignLanguage(String truffleId, String syntacticTag) { | ||
this.truffleId = truffleId; | ||
this.syntacticTag = syntacticTag; | ||
} | ||
|
||
/** @return a Truffle language ID associated with this language */ | ||
public String getTruffleId() { | ||
return truffleId; | ||
} | ||
|
||
/** | ||
* Transforms an Enso-side syntactic language tag into a recognized language object. | ||
* | ||
* @param tag the tag to parse | ||
* @return a corresponding language value, or null if the language is not recognized | ||
*/ | ||
public static ForeignLanguage getBySyntacticTag(String tag) { | ||
return Arrays.stream(values()) | ||
.filter(l -> l.syntacticTag.equals(tag)) | ||
.findFirst() | ||
.orElse(null); | ||
} | ||
} | ||
|
||
/** A parsing result. */ | ||
public static class Result { | ||
private final ForeignLanguage language; | ||
private final String foreignSource; | ||
|
||
private Result(ForeignLanguage language, String foreignSource) { | ||
this.language = language; | ||
this.foreignSource = foreignSource; | ||
} | ||
|
||
/** @return the foreign language code to eval */ | ||
public String getForeignSource() { | ||
return foreignSource; | ||
} | ||
|
||
/** @return the foreign language in which the source is written */ | ||
public ForeignLanguage getLanguage() { | ||
return language; | ||
} | ||
} | ||
|
||
/** | ||
* Parses an EPB source | ||
* | ||
* @param source the source to parse | ||
* @return the result of parsing | ||
*/ | ||
public static Result parse(Source source) { | ||
String src = source.getCharacters().toString(); | ||
String[] langAndCode = src.split(separator, 2); | ||
return new Result(ForeignLanguage.valueOf(langAndCode[0]), langAndCode[1]); | ||
} | ||
|
||
/** | ||
* Builds a new source instance that can later be parsed by this class. | ||
* | ||
* @param language the foreign language to use | ||
* @param foreignSource the foreign source to evaluate | ||
* @param name the name of the source | ||
* @return a source instance, parsable by the EPB language | ||
*/ | ||
public static Source buildSource(ForeignLanguage language, String foreignSource, String name) { | ||
return Source.newBuilder(EpbLanguage.ID, language + separator + foreignSource, name).build(); | ||
} | ||
} |
68 changes: 68 additions & 0 deletions
68
engine/runtime/src/main/java/org/enso/interpreter/epb/node/ContextRewrapNode.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
package org.enso.interpreter.epb.node; | ||
|
||
import com.oracle.truffle.api.dsl.Fallback; | ||
import com.oracle.truffle.api.dsl.GenerateUncached; | ||
import com.oracle.truffle.api.dsl.ReportPolymorphism; | ||
import com.oracle.truffle.api.dsl.Specialization; | ||
import com.oracle.truffle.api.nodes.Node; | ||
import org.enso.interpreter.epb.runtime.GuardedTruffleContext; | ||
import org.enso.interpreter.epb.runtime.PolyglotProxy; | ||
|
||
@GenerateUncached | ||
@ReportPolymorphism | ||
public abstract class ContextRewrapNode extends Node { | ||
/** | ||
* Wraps a value originating from {@code origin} into a value valid in {@code target}. This method | ||
* is allowed to use interop library on {@code value} and therefore must be called with {@code | ||
* origin} entered. | ||
* | ||
* @param value the value to wrap | ||
* @param origin the context the value originates in (and is currently entered) | ||
* @param target the context in which the value will be accessed in the future | ||
* @return a context-switch-safe wrapper for the value | ||
*/ | ||
public abstract Object execute( | ||
Object value, GuardedTruffleContext origin, GuardedTruffleContext target); | ||
|
||
@Specialization | ||
double doDouble(double d, GuardedTruffleContext origin, GuardedTruffleContext target) { | ||
return d; | ||
} | ||
|
||
@Specialization | ||
double doFloat(float d, GuardedTruffleContext origin, GuardedTruffleContext target) { | ||
return d; | ||
} | ||
|
||
@Specialization | ||
long doLong(long i, GuardedTruffleContext origin, GuardedTruffleContext target) { | ||
return i; | ||
} | ||
|
||
@Specialization | ||
long doInt(int i, GuardedTruffleContext origin, GuardedTruffleContext target) { | ||
return i; | ||
} | ||
|
||
@Specialization | ||
boolean doBoolean(boolean b, GuardedTruffleContext origin, GuardedTruffleContext target) { | ||
return b; | ||
} | ||
|
||
@Specialization(guards = "proxy.getOrigin() == target") | ||
Object doUnwrapProxy( | ||
PolyglotProxy proxy, GuardedTruffleContext origin, GuardedTruffleContext target) { | ||
return proxy.getDelegate(); | ||
} | ||
|
||
@Specialization(guards = "proxy.getTarget() == target") | ||
Object doAlreadyProxied( | ||
PolyglotProxy proxy, GuardedTruffleContext origin, GuardedTruffleContext target) { | ||
return proxy; | ||
} | ||
|
||
@Fallback | ||
Object doWrapProxy(Object o, GuardedTruffleContext origin, GuardedTruffleContext target) { | ||
return new PolyglotProxy(o, origin, target); | ||
} | ||
} |
Oops, something went wrong.