use of com.oracle.truffle.dsl.processor.java.ElementUtils.getTypeId in project graal by oracle.
the class FlatNodeGenFactory method generateAOT.
private void generateAOT(CodeTypeElement clazz) {
TypeMirror aotProviderType = new GeneratedTypeMirror(ElementUtils.getPackageName(types.GenerateAOT_Provider), "GenerateAOT.Provider");
clazz.getImplements().add(aotProviderType);
CodeExecutableElement prepare = clazz.add(CodeExecutableElement.cloneNoAnnotations(ElementUtils.findMethod(types.GenerateAOT_Provider, "prepareForAOT")));
prepare.renameArguments("language", "root");
GeneratorUtils.addOverride(prepare);
prepare.getModifiers().remove(ABSTRACT);
CodeTreeBuilder builder = prepare.createBuilder();
List<SpecializationData> filteredSpecializations = new ArrayList<>();
for (NodeData currentNode : sharingNodes) {
for (SpecializationData s : calculateReachableSpecializations(currentNode)) {
if (s.getMethod() == null || !s.isPrepareForAOT()) {
continue;
}
filteredSpecializations.add(s);
}
}
FrameState frameState = FrameState.load(this, NodeExecutionMode.SLOW_PATH, prepare);
frameState.setBoolean(AOT_STATE, true);
Map<StateBitSet, List<SpecializationData>> stateGroup = new LinkedHashMap<>();
Set<TypeGuard> implicitCasts = new LinkedHashSet<>();
for (SpecializationData specialization : filteredSpecializations) {
for (StateBitSet set : allMultiState.getSets()) {
if (set.contains(AOT_PREPARED)) {
// make sure we have an entry for a state bitset
// without any specialization but only with the AOT bit set
stateGroup.computeIfAbsent(set, (s) -> new ArrayList<>());
}
if (set.contains(specialization)) {
stateGroup.computeIfAbsent(set, (s) -> new ArrayList<>()).add(specialization);
break;
}
}
int index = 0;
for (Parameter p : specialization.getSignatureParameters()) {
TypeMirror targetType = p.getType();
Collection<TypeMirror> sourceTypes = node.getTypeSystem().lookupSourceTypes(targetType);
if (sourceTypes.size() > 1) {
implicitCasts.add(new TypeGuard(targetType, index));
}
index++;
}
}
builder.startAssert();
builder.string("!isAdoptable() || ");
builder.string("(").cast(context.getType(ReentrantLock.class), CodeTreeBuilder.singleString("getLock()"));
builder.string(").isHeldByCurrentThread()");
builder.string(" : ").doubleQuote("During prepare AST lock must be held.");
builder.end();
builder.tree(multiState.createLoad(frameState, AOT_PREPARED));
builder.tree(multiState.createLoad(frameState, filteredSpecializations.toArray()));
for (StateBitSet set : multiState.getSets()) {
if (set.contains(AOT_PREPARED)) {
builder.startIf();
builder.tree(set.createContains(frameState, AOT_PREPARED));
builder.end().startBlock();
builder.returnDefault();
builder.end();
break;
}
}
List<Object> bulkStateSet = new ArrayList<>();
Set<String> languagesChecked = new HashSet<>();
for (SpecializationData specialization : filteredSpecializations) {
// we need to copy otherwise local variables of caches may conflict.
FrameState innerFrameState = frameState.copy();
SpecializationGroup specializationGroup = SpecializationGroup.create(Arrays.asList(specialization));
for (CacheExpression cache : specialization.getCaches()) {
if (!cache.isAlwaysInitialized()) {
continue;
}
setCacheInitialized(innerFrameState, specialization, cache, true);
}
List<IfTriple> tripples = new ArrayList<>();
for (AssumptionExpression assumption : specialization.getAssumptionExpressions()) {
tripples.addAll(createAssumptionSlowPathTriples(innerFrameState, specializationGroup, assumption));
}
/*
* We don't need to materialize assumption conditions.
*/
for (IfTriple triple : tripples) {
triple.condition = null;
}
// compute guards that can be materialized
List<GuardExpression> usedGuards = new ArrayList<>();
for (GuardExpression guard : specialization.getGuards()) {
if (guardNeedsStateBit(specialization, guard)) {
bulkStateSet.add(guard);
}
if (specialization.isDynamicParameterBound(guard.getExpression(), true)) {
if (!specialization.isOnlyLanguageReferencesBound(guard.getExpression())) {
/*
* Guards with only language references can be executed.
*/
continue;
}
}
usedGuards.add(guard);
}
for (CacheExpression cache : specialization.getCaches()) {
if (!cache.isAlwaysInitialized()) {
continue;
}
if (cache.isCachedLanguage()) {
boolean needsLocal = false;
for (GuardExpression guard : usedGuards) {
if (specialization.isExpressionBindsCache(guard.getExpression(), cache)) {
needsLocal = true;
break;
}
}
if (!needsLocal) {
for (CacheExpression otherCache : specialization.getCaches()) {
if (cache == otherCache) {
continue;
}
if (specialization.isExpressionBindsCache(otherCache.getDefaultExpression(), cache)) {
needsLocal = true;
break;
}
}
}
TypeMirror languageType = cache.getLanguageType();
boolean needsCheck = false;
if (!usedGuards.isEmpty()) {
needsCheck = languagesChecked.add(ElementUtils.getTypeId(languageType));
}
CodeTreeBuilder b = builder.create();
if (needsCheck) {
b.startIf().string("language == null || language.getClass() != ").typeLiteral(languageType).end().startBlock();
b.startStatement().startStaticCall(types.CompilerDirectives, "transferToInterpreterAndInvalidate").end().end();
b.startThrow().startStaticCall(types.CompilerDirectives, "shouldNotReachHere");
b.startStaticCall(context.getType(String.class), "format");
b.doubleQuote(String.format("Specialization '%s' in node class '%s' is enabled for AOT generation. " + "The specialization declares a @%s for language class %s but was prepared for AOT with language class '%%s'. " + "Match the language used in the language reference or exclude the specialization from AOT generation with @%s.%s to resolve this problem.", getReadableSignature(specialization.getMethod()), getQualifiedName(specialization.getNode().getTemplateType()), getSimpleName(types.CachedLanguage), getQualifiedName(cache.getLanguageType()), getSimpleName(types.GenerateAOT), getSimpleName(types.GenerateAOT_Exclude)));
b.string("language != null ? language.getClass().getName() : \"null\"");
b.end();
// static call, throw,
b.end().end();
// if block
b.end();
}
if (needsLocal) {
b.startStatement();
b.type(languageType);
b.string(" ", createCacheLocalName(specialization, cache));
b.string(" = ").maybeCast(types.TruffleLanguage, cache.getLanguageType(), "language");
// statement
b.end();
}
tripples.add(new IfTriple(b.build(), null, null));
}
}
for (GuardExpression guard : usedGuards) {
Set<CacheExpression> caches = specialization.getBoundCaches(guard.getExpression(), true);
tripples.addAll(initializeCaches(innerFrameState, NodeExecutionMode.SLOW_PATH, specializationGroup, caches, true, false));
tripples.add(createMethodGuardCheck(innerFrameState, specialization, guard, NodeExecutionMode.SLOW_PATH));
}
BlockState state = IfTriple.materialize(builder, tripples, false);
builder.tree(createSpecialize(builder, innerFrameState, specializationGroup, specialization, true));
for (CacheExpression cache : specialization.getCaches()) {
if (cache.isAlwaysInitialized()) {
continue;
}
/*
* Libraries might not be AOT preparable. E.g. if a cached library was created from
* a final field of the current language. In such a case we should just not call
* prepareForAOT.
*
* Specializable nodes are always known to be preparable if they reach the code
* generator.
*/
boolean cachedLibrary = cache.isCachedLibrary();
if (cachedLibrary) {
builder.startIf().tree(createCacheReference(innerFrameState, specialization, cache)).instanceOf(aotProviderType).end().startBlock();
}
if (NodeCodeGenerator.isSpecializedNode(cache.getParameter().getType()) || cachedLibrary) {
builder.startAssert().startStaticCall(types.NodeUtil, "assertRecursion");
builder.tree(createCacheReference(innerFrameState, specialization, cache));
/*
* We allow a single recursion level only for AOT preparation. It is important
* that we only assert recursion for @Cached fields as regular AST children can
* be recursive arbitrarily deep.
*
* We might need to increase this limit in the future if it triggers to eagerly.
*/
builder.string("1");
builder.end().end();
builder.startStatement();
builder.string("(");
builder.cast(aotProviderType);
builder.tree(createCacheReference(innerFrameState, specialization, cache));
builder.string(")");
builder.string(".prepareForAOT(language, root)");
builder.end();
}
if (cachedLibrary) {
builder.end();
}
}
if (usedGuards.isEmpty()) {
bulkStateSet.add(specialization);
} else {
builder.tree(multiState.createSet(innerFrameState, new SpecializationData[] { specialization }, true, false));
}
builder.end(state.blockCount);
}
List<Object> allElements = new ArrayList<>();
allElements.add(AOT_PREPARED);
allElements.addAll(bulkStateSet);
allElements.addAll(implicitCasts);
builder.tree(multiState.createSet(frameState, allElements.toArray(), true, true));
if (!needsAOTReset()) {
return;
}
CodeExecutableElement reset = clazz.add(new CodeExecutableElement(modifiers(PRIVATE), context.getType(void.class), "resetAOT_"));
frameState = FrameState.load(this, NodeExecutionMode.FAST_PATH, reset);
reset.getModifiers().remove(ABSTRACT);
builder = reset.createBuilder();
for (StateBitSet set : multiState.all) {
if (set.contains(AOT_PREPARED)) {
builder.tree(set.createLoad(frameState));
builder.startIf();
builder.tree(set.createNotContains(frameState, AOT_PREPARED));
builder.end().startBlock();
builder.returnDefault();
builder.end();
}
break;
}
for (SpecializationData specialization : filteredSpecializations) {
List<CacheExpression> resetCaches = new ArrayList<>();
for (CacheExpression cache : specialization.getCaches()) {
if (cache.isAlwaysInitialized()) {
continue;
}
if (types.Profile != null && ElementUtils.isAssignable(cache.getParameter().getType(), types.Profile)) {
resetCaches.add(cache);
}
}
if (resetCaches.size() > 0) {
builder.tree(multiState.createLoadAll(frameState, specialization));
builder.startIf().tree(multiState.createContainsAll(frameState, new Object[] { specialization })).end();
builder.startBlock();
for (CacheExpression cache : resetCaches) {
builder.startStatement();
builder.tree(createCacheReference(frameState, specialization, cache));
builder.string(".reset()");
builder.end();
}
builder.end();
}
}
for (StateBitSet set : multiState.getSets()) {
builder.tree(set.createSetZero(frameState, true));
}
if (requiresExclude()) {
builder.tree(exclude.createSetZero(frameState, true));
}
/*
* It is important that we reset the state first before we clear the caches for initialized
* libraries. Otherwise we might observe an enabled specialization without initialized cache
* on the fast-path.
*/
for (SpecializationData specialization : filteredSpecializations) {
boolean resetSpecializationClass = false;
for (CacheExpression cache : specialization.getCaches()) {
if (cache.isAlwaysInitialized()) {
continue;
}
if (cache.isCachedLibraryManuallyDispatched()) {
if (useSpecializationClass(specialization)) {
resetSpecializationClass = true;
break;
}
builder.startStatement();
builder.tree(createCacheReference(frameState, specialization, cache)).string(" = null");
builder.end();
}
}
if (resetSpecializationClass || specialization.hasMultipleInstances()) {
builder.startStatement();
builder.string("this.", createSpecializationFieldName(specialization));
builder.string(" = null");
builder.end();
}
}
}
Aggregations