Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.oracle.truffle.polyglot.PolyglotReferences Maven / Gradle / Ivy
Go to download
Truffle is a multi-language framework for executing dynamic languages
that achieves high performance when combined with Graal.
/*
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The Universal Permissive License (UPL), Version 1.0
*
* Subject to the condition set forth below, permission is hereby granted to any
* person obtaining a copy of this software, associated documentation and/or
* data (collectively the "Software"), free of charge and under any and all
* copyright rights in the Software, and any and all patent rights owned or
* freely licensable by each licensor hereunder covering either (i) the
* unmodified Software as contributed to or provided by such licensor, or (ii)
* the Larger Works (as defined below), to deal in both
*
* (a) the Software, and
*
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
* one is included with the Software each a "Larger Work" to which the Software
* is contributed by such licensors),
*
* without restriction, including without limitation the rights to copy, create
* derivative works of, display, perform, and distribute the Software and make,
* use, sell, offer for sale, import, export, have made, and have sold the
* Software and the Larger Work(s), and to sublicense the foregoing rights on
* either these or other terms.
*
* This license is subject to the following condition:
*
* The above copyright notice and either this complete permission notice or at a
* minimum a reference to the UPL must be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.oracle.truffle.polyglot;
import java.lang.ref.WeakReference;
import com.oracle.truffle.api.Assumption;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
import com.oracle.truffle.api.TruffleLanguage;
import com.oracle.truffle.api.TruffleLanguage.ContextPolicy;
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
import com.oracle.truffle.api.TruffleLanguage.LanguageReference;
import com.oracle.truffle.api.TruffleStackTrace;
import com.oracle.truffle.api.TruffleStackTraceElement;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.source.SourceSection;
final class PolyglotReferences {
private PolyglotReferences() {
// no instances
}
static AbstractContextReference createAlwaysSingleContext(PolyglotLanguage language, boolean strong) {
if (strong) {
return new StrongSingleContext(language);
} else {
return new WeakSingleContext(language);
}
}
static AbstractContextReference createAssumeSingleContext(PolyglotLanguage language,
Assumption validIf0,
Assumption validIf1,
ContextReference fallback, boolean strong) {
assert !(fallback instanceof WeakSingleContext) && !(fallback instanceof StrongSingleContext);
return new AssumeSingleContext(language, validIf0, validIf1, fallback, strong);
}
static AbstractContextReference createAlwaysMultiContext(PolyglotLanguage language) {
return new MultiContextSupplier(language);
}
static LanguageReference> createAlwaysSingleLanguage(PolyglotLanguage language, PolyglotLanguageInstance initValue) {
return new SingleLanguage(language, initValue);
}
static LanguageReference> createAssumeSingleLanguage(PolyglotLanguage language,
PolyglotLanguageInstance initValue,
Assumption validIf,
LanguageReference> fallback) {
assert !(fallback instanceof SingleLanguage);
return new AssumeSingleLanguage(language, initValue, validIf, fallback);
}
static LanguageReference> createAlwaysMultiLanguage(PolyglotLanguage language) {
return new MultiLanguageSupplier(language);
}
static AssertionError invalidSharingError(PolyglotEngineImpl usedEngine) throws AssertionError {
Exception e = new Exception();
StringBuilder stack = new StringBuilder();
Exception exceptionCreating = null;
try {
TruffleStackTrace.fillIn(e);
ContextPolicy prevPolicy = null;
for (TruffleStackTraceElement stackTrace : TruffleStackTrace.getStackTrace(e)) {
RootNode root = stackTrace.getTarget().getRootNode();
PolyglotEngineImpl engine = (PolyglotEngineImpl) EngineAccessor.NODES.getPolyglotEngine(root);
if (engine != null && usedEngine != engine) {
// different engine different assertion
break;
}
PolyglotLanguageInstance instance = lookupLanguageInstance(root);
ContextPolicy policy = instance.language.getEffectiveContextPolicy(instance.language);
SourceSection sourceSection = null;
Node location = stackTrace.getLocation();
if (location != null) {
sourceSection = location.getEncapsulatingSourceSection();
}
if (sourceSection == null) {
sourceSection = root.getSourceSection();
}
if ((prevPolicy == ContextPolicy.EXCLUSIVE || policy == ContextPolicy.EXCLUSIVE) && prevPolicy != policy && prevPolicy != null) {
stack.append(String.format(" <-- Likely Invalid Sharing --> %n"));
}
stack.append(String.format(" %-9s %s%n", policy, createJavaStackFrame(instance.language, root.getName(), sourceSection)));
prevPolicy = policy;
}
} catch (Exception ex) {
exceptionCreating = ex;
}
AssertionError error = new AssertionError(String.format("Invalid sharing of runtime values in AST nodes detected.Stack trace: %n%s", stack.toString()));
if (exceptionCreating != null) {
error.addSuppressed(exceptionCreating);
}
throw error;
}
static StackTraceElement createJavaStackFrame(PolyglotLanguage language, String rootName, SourceSection sourceLocation) {
String declaringClass = "<" + language.getId() + ">";
String methodName = rootName == null ? "" : rootName;
String fileName = sourceLocation != null ? sourceLocation.getSource().getName() : "Unknown";
int startLine = sourceLocation != null ? sourceLocation.getStartLine() : -1;
return new StackTraceElement(declaringClass, methodName, fileName, startLine);
}
private static PolyglotLanguageInstance lookupLanguageInstance(RootNode root) {
TruffleLanguage> spi = EngineAccessor.NODES.getLanguage(root);
if (spi != null) {
return (PolyglotLanguageInstance) EngineAccessor.LANGUAGE.getPolyglotLanguageInstance(spi);
}
return null;
}
private static boolean assertDirectContextAccess(PolyglotLanguageContext languageContext, Object languageContextImpl) throws AssertionError {
if (languageContext == null) {
/*
* This case may happen if the assertions were disabled during boot image generation but
* were later enabled at runtime. See GR-14463.
*/
return true;
}
PolyglotContextImpl otherContext = PolyglotContextImpl.requireContext();
PolyglotLanguageContext otherLanguageContext = otherContext.getContext(languageContext.language);
boolean valid = otherLanguageContext.getContextImpl() == languageContextImpl;
if (!valid) {
throw invalidSharingError(languageContext.getEngine());
}
return true;
}
private static boolean checkContextCollected(Object context) {
if (context == null) {
throw invalidSharingError(null);
}
return true;
}
private static final class SingleLanguage extends LanguageReference> {
private final PolyglotLanguage language;
@CompilationFinal private TruffleLanguage spi;
@SuppressWarnings("unchecked")
SingleLanguage(PolyglotLanguage language, PolyglotLanguageInstance initValue) {
this.language = language;
this.spi = initValue != null ? initValue.spi : null;
}
@SuppressWarnings("unchecked")
@Override
public TruffleLanguage get() {
assert language.assertCorrectEngine();
TruffleLanguage languageSpi = this.spi;
if (languageSpi == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
this.spi = languageSpi = language.getCurrentLanguageContext().getLanguageInstance().spi;
}
assert assertDirectLanguageAccess(this.language, languageSpi);
return languageSpi;
}
private static boolean assertDirectLanguageAccess(PolyglotLanguage language, TruffleLanguage seenLanguage) {
TruffleLanguage> conservativeLanguage = language.getConservativeLanguageReference().get();
if (conservativeLanguage != seenLanguage) {
throw invalidSharingError(language.getEngine());
}
return true;
}
}
private static final class WeakSingleContext extends AbstractContextReference {
private final PolyglotLanguage language;
@CompilationFinal private volatile WeakReference languageContextImpl;
// only set if assertions are enabled
private volatile WeakReference languageContext;
WeakSingleContext(PolyglotLanguage language) {
this.language = language;
}
@Override
public Object get() {
assert language.assertCorrectEngine();
WeakReference ref = languageContextImpl;
if (ref == null) {
CompilerDirectives.transferToInterpreterAndInvalidate();
ref = initialize(language.getCurrentLanguageContext());
}
Object context = ref.get();
assert checkContextCollected(context);
assert assertDirectContextAccess(context, this.languageContext);
return context;
}
private WeakReference initialize(PolyglotLanguageContext langContext) {
WeakReference ref;
assert setLanguageContext(langContext);
this.languageContextImpl = ref = new WeakReference<>(langContext.getContextImpl());
return ref;
}
private static boolean assertDirectContextAccess(Object seenContext, WeakReference contextRef) {
if (contextRef == null) {
/*
* This case may happen if the assertions were disabled during boot image generation
* but were later enabled at runtime. See GR-14463.
*/
return true;
}
PolyglotLanguageContext context = contextRef.get();
if (context == null) {
throw invalidSharingError(null);
}
return PolyglotReferences.assertDirectContextAccess(context, seenContext);
}
private boolean setLanguageContext(PolyglotLanguageContext langContext) {
this.languageContext = new WeakReference<>(langContext);
return true;
}
}
private static final class StrongSingleContext extends AbstractContextReference {
private static final Object NO_CONTEXT = new Object();
private final PolyglotLanguage language;
@CompilationFinal private volatile Object languageContextImpl = NO_CONTEXT;
// only set if assertions are enabled
private volatile PolyglotLanguageContext languageContext;
StrongSingleContext(PolyglotLanguage language) {
this.language = language;
}
@Override
public Object get() {
assert language.assertCorrectEngine();
Object context = languageContextImpl;
if (context == NO_CONTEXT) {
CompilerDirectives.transferToInterpreterAndInvalidate();
context = initialize(language.getCurrentLanguageContext());
}
assert checkContextCollected(context);
assert assertDirectContextAccess(this.languageContext, context);
return context;
}
private Object initialize(PolyglotLanguageContext langContext) {
Object context;
assert setLanguageContext(langContext);
this.languageContextImpl = context = langContext.getContextImpl();
return context;
}
private boolean setLanguageContext(PolyglotLanguageContext langContext) {
this.languageContext = langContext;
return true;
}
}
private static final class AssumeSingleContext extends AbstractContextReference {
private final ContextReference singleContextReference;
private final ContextReference fallbackReference;
private final Assumption validIf0;
private final Assumption validIf1;
AssumeSingleContext(PolyglotLanguage language, Assumption validIf0, Assumption validIf1, ContextReference fallback, boolean strong) {
this.validIf0 = validIf0;
this.validIf1 = validIf1;
this.singleContextReference = createAlwaysSingleContext(language, strong);
this.fallbackReference = fallback;
}
@Override
public Object get() {
Object context;
if ((validIf0 == null || validIf0.isValid()) && (validIf1 == null || validIf1.isValid())) {
context = singleContextReference.get();
} else {
context = fallbackReference.get();
}
assert fallbackReference.get() == context;
return context;
}
}
private static final class AssumeSingleLanguage extends LanguageReference> {
private final LanguageReference> singleLanguageReference;
private final LanguageReference> fallbackReference;
private final Assumption singleLanguage;
AssumeSingleLanguage(PolyglotLanguage language, PolyglotLanguageInstance initValue, Assumption singleContextAssumption, LanguageReference> fallbackReference) {
this.singleLanguage = singleContextAssumption;
this.singleLanguageReference = createAlwaysSingleLanguage(language, initValue);
this.fallbackReference = fallbackReference;
}
@Override
public TruffleLanguage get() {
if (singleLanguage.isValid()) {
return singleLanguageReference.get();
}
return fallbackReference.get();
}
}
private static final class MultiLanguageSupplier extends LanguageReference> {
final PolyglotLanguage language;
MultiLanguageSupplier(PolyglotLanguage language) {
this.language = language;
}
@SuppressWarnings("unchecked")
@Override
public TruffleLanguage get() {
assert language.assertCorrectEngine();
return PolyglotContextImpl.currentEntered(language.engine).getContext(language).getLanguageInstance().spi;
}
}
private static final class MultiContextSupplier extends AbstractContextReference {
final PolyglotLanguage language;
MultiContextSupplier(PolyglotLanguage language) {
this.language = language;
}
@Override
public Object get() {
assert language.assertCorrectEngine();
return PolyglotContextImpl.currentEntered(language.engine).getContextImpl(language);
}
}
abstract static class AbstractContextReference extends ContextReference {
}
}