Skip to content

Commit

Permalink
Remove abstractions over different conditions
Browse files Browse the repository at this point in the history
  • Loading branch information
vjovanov committed May 24, 2024
1 parent 4ebb6ce commit a89a95f
Show file tree
Hide file tree
Showing 19 changed files with 107 additions and 230 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@
import java.lang.reflect.Parameter;
import java.lang.reflect.RecordComponent;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Function;

import org.graalvm.nativeimage.ImageSingletons;
Expand All @@ -43,7 +41,6 @@

import com.oracle.svm.core.SubstrateUtil;
import com.oracle.svm.core.c.NonmovableArrays;
import com.oracle.svm.core.configure.RuntimeCondition;
import com.oracle.svm.core.configure.RuntimeConditionSet;
import com.oracle.svm.core.feature.AutomaticallyRegisteredImageSingleton;
import com.oracle.svm.core.hub.DynamicHub;
Expand Down Expand Up @@ -381,11 +378,7 @@ private static Object decodeField(UnsafeArrayTypeReader buf, Class<?> declaringC

private static RuntimeConditionSet decodeConditions(UnsafeArrayTypeReader buf) {
var conditionTypes = decodeArray(buf, Class.class, i -> decodeType(buf));
Set<RuntimeCondition> runtimeConditions = new HashSet<>(conditionTypes.length);
for (Class<?> conditionType : conditionTypes) {
runtimeConditions.add(RuntimeCondition.createTypeReachedCondition(conditionType));
}
return RuntimeConditionSet.createRuntime(runtimeConditions);
return RuntimeConditionSet.createDecoded(conditionTypes);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,9 @@ public static final class Options {
@Option(help = "Testing flag: the typeReachable condition is treated as typeReached so the semantics of programs can change.")//
public static final HostedOptionKey<Boolean> TreatAllTypeReachableConditionsAsTypeReached = new HostedOptionKey<>(false);

@Option(help = "Testing flag: the name is treated as type to test what happens.")//
public static final HostedOptionKey<Boolean> TreatAllNameEntriesAsType = new HostedOptionKey<>(false);

@Option(help = "Testing flag: the typeReached condition is always satisfied however it prints the stack traces where it would not be satisfied.")//
public static final HostedOptionKey<Boolean> TrackUnsatisfiedTypeReachedConditions = new HostedOptionKey<>(false);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*/
package com.oracle.svm.core.configure;

import static com.oracle.svm.core.configure.ConfigurationFiles.Options.TreatAllNameEntriesAsType;
import static com.oracle.svm.core.configure.ConfigurationFiles.Options.TreatAllTypeReachableConditionsAsTypeReached;
import static org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition.TYPE_REACHABLE_KEY;
import static org.graalvm.nativeimage.impl.UnresolvedConfigurationCondition.TYPE_REACHED_KEY;
Expand Down Expand Up @@ -215,7 +216,7 @@ protected UnresolvedConfigurationCondition parseCondition(EconomicMap<String, Ob

if (conditionObject.containsKey(TYPE_REACHED_KEY)) {
if (!runtimeCondition) {
failOnSchemaError("'" + TYPE_REACHED_KEY + "' condition can not be used in older schemas. Please migrate to the latest schema.");
failOnSchemaError("'" + TYPE_REACHED_KEY + "' condition cannot be used in older schemas. Please migrate the file to the latest schema.");
}
Object object = conditionObject.get(TYPE_REACHED_KEY);
var condition = parseTypeContents(object);
Expand All @@ -224,7 +225,7 @@ protected UnresolvedConfigurationCondition parseCondition(EconomicMap<String, Ob
return UnresolvedConfigurationCondition.create(className, true);
}
} else if (conditionObject.containsKey(TYPE_REACHABLE_KEY)) {
if (runtimeCondition) {
if (runtimeCondition && !TreatAllTypeReachableConditionsAsTypeReached.getValue()) {
failOnSchemaError("'" + TYPE_REACHABLE_KEY + "' condition can not be used with the latest schema. Please use '" + TYPE_REACHED_KEY + "'.");
}
Object object = conditionObject.get(TYPE_REACHABLE_KEY);
Expand All @@ -248,7 +249,7 @@ protected static Optional<ConfigurationTypeDescriptor> parseTypeOrName(EconomicM
if (typeObject != null) {
return parseTypeContents(typeObject);
} else if (name != null) {
return Optional.of(new NamedConfigurationTypeDescriptor(asString(name)));
return Optional.of(new NamedConfigurationTypeDescriptor(asString(name), TreatAllNameEntriesAsType.getValue()));
} else {
throw failOnSchemaError("must have type or name specified for an element");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,5 @@ static String checkQualifiedJavaName(String javaName) {
return canonicalizeTypeName(javaName);
}

boolean isType();
boolean definedAsType();
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,20 @@

import com.oracle.svm.core.util.json.JsonWriter;

public record NamedConfigurationTypeDescriptor(String name, boolean type) implements ConfigurationTypeDescriptor {
public record NamedConfigurationTypeDescriptor(String name, boolean definedAsType) implements ConfigurationTypeDescriptor {

public NamedConfigurationTypeDescriptor(String name) {
this(name, false);
}

public NamedConfigurationTypeDescriptor(String name, boolean type) {
public NamedConfigurationTypeDescriptor(String name, boolean definedAsType) {
this.name = ConfigurationTypeDescriptor.checkQualifiedJavaName(name);
this.type = type;
this.definedAsType = definedAsType;
}

@Override
public boolean isType() {
return type;
public boolean definedAsType() {
return definedAsType;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public int compareTo(ConfigurationTypeDescriptor other) {
}

@Override
public boolean isType() {
public boolean definedAsType() {
return true;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ private void parseClass(EconomicMap<String, Object> data) {
if (type.isEmpty()) {
return;
}
boolean isType = type.get().isType();
boolean isType = type.get().definedAsType();

UnresolvedConfigurationCondition unresolvedCondition = parseCondition(data, isType);
TypeResult<C> conditionResult = conditionResolver.resolveCondition(unresolvedCondition);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -30,43 +30,40 @@
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.graalvm.nativeimage.Platform;
import org.graalvm.nativeimage.Platforms;
import org.graalvm.nativeimage.impl.ConfigurationCondition;

import com.oracle.svm.core.hub.DynamicHub;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.util.LogUtils;

/**
* Represents a group of {@link RuntimeCondition}s that guard a value.
* Represents a group of {@link #conditions} that guard a value. The conditions are encoded
* <p>
* If any of the {@link #conditions} is satisfied then the whole set becomes also
* {@link #satisfied}. {@link RuntimeConditionSet}s can be created at build time
* {@link #createHosted(ConfigurationCondition...)} and stored to the image heap, or it can be
* encoded ({@link #getTypesForEncoding()} and later decoded at run time
* ({@link #createRuntime(Set)}. The current implementation does not cache {@link #conditions},
* although this will be implemented in the future (GR-49526)
* {@link #createHosted(ConfigurationCondition)} and stored to the image heap, or it can be encoded
* ({@link #getTypesForEncoding()} and later decoded at run time ({@link #createDecoded(Object[])}.
* The current implementation does not cache {@link #conditions}, although this will be implemented
* in the future (GR-49526)
*/
public class RuntimeConditionSet {

private RuntimeCondition[] conditions;
private Object[] conditions;
private boolean satisfied;

@Platforms(Platform.HOSTED_ONLY.class)
public static RuntimeConditionSet createHosted(ConfigurationCondition... conditions) {
var conditionSet = new RuntimeConditionSet(Set.of());
for (ConfigurationCondition condition : conditions) {
conditionSet.addCondition(condition);
}
return conditionSet;
public static RuntimeConditionSet emptySet() {
return new RuntimeConditionSet(new Object[0]);
}

@Platforms(Platform.HOSTED_ONLY.class)
public static RuntimeConditionSet unmodifiableEmptySet() {
return UnmodifiableRuntimeConditionSet.UNMODIFIABLE_EMPTY_SET;
public static RuntimeConditionSet createHosted(ConfigurationCondition condition) {
var conditionSet = new RuntimeConditionSet(new Object[0]);
conditionSet.addCondition(condition);
return conditionSet;
}

@Platforms(Platform.HOSTED_ONLY.class)
Expand All @@ -80,10 +77,10 @@ public synchronized void addCondition(ConfigurationCondition cnd) {
return;
}

RuntimeCondition newRuntimeCondition = RuntimeCondition.create(cnd);
Stream<RuntimeCondition> existingConditions = conditions == null ? Stream.empty() : Arrays.stream(conditions);
setConditions(Stream.concat(existingConditions, Stream.of(newRuntimeCondition))
.collect(Collectors.toSet()));
Object newRuntimeCondition = createRuntimeCondition(cnd);
Set<Object> existingConditions = conditions == null ? new HashSet<>() : new HashSet<>(Arrays.asList(conditions));
existingConditions.add(newRuntimeCondition);
setConditions(existingConditions.toArray());
}

@Platforms(Platform.HOSTED_ONLY.class)
Expand All @@ -92,28 +89,19 @@ public Set<Class<?>> getTypesForEncoding() {
return Set.of();
} else {
Set<Class<?>> types = new HashSet<>();
for (RuntimeCondition condition : conditions) {
types.addAll(condition.getTypesForEncoding());
for (Object condition : conditions) {
types.addAll(getTypesForEncoding(condition));
}
return types;
}
}

public static RuntimeConditionSet createRuntime(Set<RuntimeCondition> conditions) {
return new RuntimeConditionSet(conditions);
}

private RuntimeConditionSet(Set<RuntimeCondition> conditions) {
setConditions(conditions);
public static RuntimeConditionSet unmodifiableEmptySet() {
return UnmodifiableRuntimeConditionSet.UNMODIFIABLE_EMPTY_SET;
}

private void setConditions(Set<RuntimeCondition> conditions) {
if (conditions.isEmpty()) {
this.conditions = null;
} else {
this.conditions = conditions.toArray(RuntimeCondition[]::new);
}
satisfied = false;
public static RuntimeConditionSet createDecoded(Object[] conditions) {
return new RuntimeConditionSet(conditions);
}

/**
Expand All @@ -133,8 +121,8 @@ public boolean satisfied() {
if (localConditions == null) {
result = true;
} else {
for (RuntimeCondition condition : localConditions) {
if (condition.isSatisfied()) {
for (Object condition : localConditions) {
if (isSatisfied(condition)) {
conditions = null;
satisfied = result = true;
break;
Expand All @@ -158,10 +146,46 @@ public String toString() {
return conditionsString + " = " + satisfied;
}

private RuntimeConditionSet(Object[] conditions) {
setConditions(conditions);
}

private void setConditions(Object[] conditions) {
if (conditions.length == 0) {
this.conditions = null;
} else {
this.conditions = conditions;
}
satisfied = false;
}

private static Object createRuntimeCondition(ConfigurationCondition cnd) {
if (cnd.isAlwaysTrue() || !cnd.isRuntimeChecked()) {
throw VMError.shouldNotReachHere("We should never create run-time conditions from conditions that are always true at build time. Condition: " + cnd);
}
return cnd.getType();
}

private static boolean isSatisfied(Object condition) {
if (condition instanceof Class<?> typeReachedCondition) {
return DynamicHub.fromClass(typeReachedCondition).isReached();
} else {
throw VMError.shouldNotReachHere("Only typeReached condition is supported.");
}
}

private static Set<Class<?>> getTypesForEncoding(Object condition) {
if (condition instanceof Class<?> res) {
return Set.of(res);
} else {
throw VMError.shouldNotReachHere("Only typeReached condition is supported.");
}
}

public static final class UnmodifiableRuntimeConditionSet extends RuntimeConditionSet {
private static final RuntimeConditionSet UNMODIFIABLE_EMPTY_SET = new UnmodifiableRuntimeConditionSet(Set.of());
private static final RuntimeConditionSet UNMODIFIABLE_EMPTY_SET = new UnmodifiableRuntimeConditionSet(new Object[0]);

private UnmodifiableRuntimeConditionSet(Set<RuntimeCondition> conditions) {
private UnmodifiableRuntimeConditionSet(Object[] conditions) {
super(conditions);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ private void parseSerializationDescriptorObject(EconomicMap<String, Object> data
return;
}

UnresolvedConfigurationCondition unresolvedCondition = parseCondition(data, targetSerializationClass.get().isType());
UnresolvedConfigurationCondition unresolvedCondition = parseCondition(data, targetSerializationClass.get().definedAsType());
var condition = conditionResolver.resolveCondition(unresolvedCondition);
if (!condition.isPresent()) {
return;
Expand Down
Loading

0 comments on commit a89a95f

Please sign in to comment.