Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,8 @@
import com.oracle.truffle.api.nodes.ExplodeLoop;
import com.oracle.truffle.api.nodes.Node;
import com.oracle.truffle.api.nodes.RootNode;
import com.oracle.truffle.api.nodes.SlowPathException;
import com.oracle.truffle.api.nodes.UnexpectedResultException;
import com.oracle.truffle.api.object.DynamicObject;
import com.oracle.truffle.api.object.PropertyGetter;
import com.oracle.truffle.api.object.Shape;
Expand Down Expand Up @@ -2015,82 +2017,157 @@ public static boolean canBeSpecialMethod(TruffleString key) {
return TpSlots.canBeSpecialMethod(key, CodePointLengthNode.getUncached(), CodePointAtIndexUTF32Node.getUncached());
}

public static Object getValue(PropertyGetter getter, PythonObject obj) {
public static Object getValue(PropertyGetter getter, PythonObject obj) throws FastPathBailoutException {
assert obj.checkDictFlags();
return getter.get(obj);
Object value = getter.get(obj);
if (value == PNone.NO_VALUE) {
throw FastPathBailoutException.INSTANCE;
}
return value;
}

public static int getIntValue(PropertyGetter getter, PythonObject obj) throws FastPathBailoutException, UnexpectedResultException {
assert obj.checkDictFlags();
try {
return getter.getInt(obj);
} catch (UnexpectedResultException e) {
if (e.getResult() == PNone.NO_VALUE) {
throw FastPathBailoutException.INSTANCE;
}
throw e;
}
}

public static final class FastPathBailoutException extends SlowPathException {
private static final long serialVersionUID = 8275772171120097556L;
private static final FastPathBailoutException INSTANCE = new FastPathBailoutException();

private FastPathBailoutException() {
}
}

@Specialization(guards = {
"!canBeSpecialMethod(cachedKey)", //
"!hasMaterializedDict(cachedShape)", "isBuiltinModule(cachedShape)", //
"getter != null", "getter.accepts(receiver)"}, //
rewriteOn = {FastPathBailoutException.class, UnexpectedResultException.class}, limit = "3")
static int doModuleInt(TruffleString key, PythonModule receiver,
@Cached("key") TruffleString cachedKey,
@Cached("receiver.getShape()") Shape cachedShape,
@Cached("getPropertyGetterWithFinalAssumption(cachedShape, key)") PropertyGetter getter) throws FastPathBailoutException, UnexpectedResultException {
assert key == cachedKey; // should be a constant operand
return getIntValue(getter, receiver);
}

@ForceQuickening
@Specialization(guards = {
"!canBeSpecialMethod(cachedKey)", //
"!hasMaterializedDict(cachedShape)", "isBuiltinModule(cachedShape)", //
"getter != null", "getter.accepts(receiver)", //
"!isNoValue(value)"}, limit = "3")
"getter != null", "getter.accepts(receiver)"}, //
replaces = "doModuleInt", rewriteOn = FastPathBailoutException.class, limit = "3")
static Object doModule(TruffleString key, PythonModule receiver,
@Cached("key") TruffleString cachedKey,
@Cached("receiver.getShape()") Shape cachedShape,
@Cached("getPropertyGetterWithFinalAssumption(cachedShape, key)") PropertyGetter getter,
@Bind("getValue(getter, receiver)") Object value) {
@Cached("getPropertyGetterWithFinalAssumption(cachedShape, key)") PropertyGetter getter) throws FastPathBailoutException {
assert key == cachedKey; // should be a constant operand
return value;
return getValue(getter, receiver);
}

// For type instance field: for builtin type we know descriptors only have dunder names
// (__xxx__), so we can skip descriptor check + we need to check the __get__ (tp_descr_get)
// on the resulting value (this is common situation)
public static Object loadTypeInstanceValue(VirtualFrame frame, Node inliningTarget, PythonManagedClass object, GetObjectSlotsNode getValueSlotsNode,
CallSlotDescrGet callSlotDescrGet, PropertyGetter cachedPropertyGetter, InlinedBranchProfile hasNonDescriptorValueProfile) {
CallSlotDescrGet callSlotDescrGet, PropertyGetter cachedPropertyGetter, InlinedBranchProfile hasNonDescriptorValueProfile) throws FastPathBailoutException {
assert object.checkDictFlags();
Object value = cachedPropertyGetter.get(object);
if (value != PNone.NO_VALUE) {
if (value != PNone.NO_VALUE && value != null) {
var valueGet = getValueSlotsNode.execute(inliningTarget, value).tp_descr_get();
if (valueGet == null) {
hasNonDescriptorValueProfile.enter(inliningTarget);
return value;
} else {
return callSlotDescrGet.execute(frame, inliningTarget, valueGet, value, PNone.NO_VALUE, object);
Object result = callSlotDescrGet.execute(frame, inliningTarget, valueGet, value, PNone.NO_VALUE, object);
if (result != null) {
return result;
}
}
}
return null;
throw FastPathBailoutException.INSTANCE;
}

@Idempotent
public static boolean isBuiltinType(Shape cachedShape) {
return cachedShape.getDynamicType() == PythonBuiltinClassType.PythonClass;
}

@Specialization(guards = {
"!canBeSpecialMethod(cachedKey)", //
"!hasMaterializedDict(cachedShape)", "isBuiltinType(cachedShape)", //
"getter != null", "getter.accepts(receiver)"}, //
rewriteOn = {FastPathBailoutException.class, UnexpectedResultException.class}, limit = "3")
static int doTypeInt(@SuppressWarnings("unused") VirtualFrame frame, TruffleString key, PythonManagedClass receiver,
@Bind Node inliningTarget,
@Cached("key") TruffleString cachedKey,
@Cached("receiver.getShape()") Shape cachedShape,
@Cached("getPropertyGetterWithFinalAssumption(cachedShape, key)") PropertyGetter getter,
@SuppressWarnings("unused") @Shared("typeGetObjectSlots") @Cached GetObjectSlotsNode getObjectSlotsNode,
@SuppressWarnings("unused") @Shared("typeCallSlotDescrGet") @Cached CallSlotDescrGet callSlotDescrGet,
@SuppressWarnings("unused") @Shared("typeNonDescriptorProfile") @Cached InlinedBranchProfile hasNonDescriptorValueProfile) throws FastPathBailoutException,
UnexpectedResultException {
assert key == cachedKey; // should be a constant operand
// A primitive int cannot itself be a descriptor, so the direct field value is final.
return getIntValue(getter, receiver);
}

@ForceQuickening
@StoreBytecodeIndex // we may be calling the descriptor
@Specialization(guards = {
"!canBeSpecialMethod(cachedKey)", //
"!hasMaterializedDict(cachedShape)", "isBuiltinType(cachedShape)", //
"getter != null", "getter.accepts(receiver)", //
"value != null"}, limit = "3")
"getter != null", "getter.accepts(receiver)"}, //
replaces = "doTypeInt", rewriteOn = FastPathBailoutException.class, limit = "3")
static Object doType(VirtualFrame frame, TruffleString key, PythonManagedClass receiver,
@Bind Node inliningTarget,
@Cached("key") TruffleString cachedKey,
@Cached("receiver.getShape()") Shape cachedShape,
@Cached("getPropertyGetterWithFinalAssumption(cachedShape, key)") PropertyGetter getter,
@Cached GetObjectSlotsNode getObjectSlotsNode,
@Cached CallSlotDescrGet callSlotDescrGet,
@Cached InlinedBranchProfile hasNonDescriptorValueProfile,
@Bind("loadTypeInstanceValue(frame, $node, receiver, getObjectSlotsNode, callSlotDescrGet, getter, hasNonDescriptorValueProfile)") Object value) {
@Shared("typeGetObjectSlots") @Cached GetObjectSlotsNode getObjectSlotsNode,
@Shared("typeCallSlotDescrGet") @Cached CallSlotDescrGet callSlotDescrGet,
@Shared("typeNonDescriptorProfile") @Cached InlinedBranchProfile hasNonDescriptorValueProfile) throws FastPathBailoutException {
assert key == cachedKey; // should be a constant operand
return value;
return loadTypeInstanceValue(frame, inliningTarget, receiver, getObjectSlotsNode, callSlotDescrGet, getter, hasNonDescriptorValueProfile);
}

// The convention is that if klass is null, then the object is assumed to be of a builtin type that has the object's or module's tp_getattro - we do not need to recheck that dynamically
public static Object loadInstanceValue(Node inliningTarget, PythonObject object, PythonManagedClass klass,
TruffleString key, LookupAttributeInMRONode.CachedKeyFastPath getDesc, Shape cachedShape, PropertyGetter cachedPropertyGetter,
InlineWeakValueProfile slotsValueProfile) {
InlineWeakValueProfile slotsValueProfile) throws FastPathBailoutException {
checkCanLoadInstanceValue(inliningTarget, object, klass, key, getDesc, cachedShape, slotsValueProfile);
Object value = cachedPropertyGetter.get(object);
if (value == PNone.NO_VALUE) {
throw FastPathBailoutException.INSTANCE;
}
return value;
}

public static int loadInstanceValueInt(Node inliningTarget, PythonObject object, PythonManagedClass klass,
TruffleString key, LookupAttributeInMRONode.CachedKeyFastPath getDesc, Shape cachedShape, PropertyGetter cachedPropertyGetter,
InlineWeakValueProfile slotsValueProfile) throws FastPathBailoutException, UnexpectedResultException {
checkCanLoadInstanceValue(inliningTarget, object, klass, key, getDesc, cachedShape, slotsValueProfile);
return getIntValue(cachedPropertyGetter, object);
}

private static void checkCanLoadInstanceValue(Node inliningTarget, PythonObject object, PythonManagedClass klass,
TruffleString key, LookupAttributeInMRONode.CachedKeyFastPath getDesc, Shape cachedShape,
InlineWeakValueProfile slotsValueProfile) throws FastPathBailoutException {
if (klass == null || hasObjectOrModuleGetattro(inliningTarget, klass, slotsValueProfile)) {
Object descr = getDesc.execute(inliningTarget, cachedShape.getDynamicType(), key);
if (descr == PNone.NO_VALUE) {
assert object.checkDictFlags();
Object value = cachedPropertyGetter.get(object);
return value == PNone.NO_VALUE ? null : value;
return;
}
}
return null;
throw FastPathBailoutException.INSTANCE;
}

private static boolean hasObjectOrModuleGetattro(Node inliningTarget, PythonManagedClass klass, InlineWeakValueProfile slotsValueProfile) {
Expand All @@ -2111,23 +2188,37 @@ public static boolean isBuiltinWithObjectOrModuleGetattro(Shape cachedShape) {
return cachedShape.getDynamicType() instanceof PythonBuiltinClassType type && hasObjectOrModuleGetattro(type.getSlots());
}

@StoreBytecodeIndex // looking up attribute in MRO may have side effects
@Specialization(guards = {
"!hasMaterializedDict(cachedShape)", "managedClass != null || isBuiltinWithObjectOrModuleGetattro(cachedShape)", //
"getter != null", "getter.accepts(receiver)"}, //
rewriteOn = {FastPathBailoutException.class, UnexpectedResultException.class}, limit = "3")
static int doInstanceValueInt(TruffleString key, PythonObject receiver,
@Bind Node inliningTarget,
@Cached("receiver.getShape()") Shape cachedShape,
@Cached("getManagedClassOrNull(cachedShape)") PythonManagedClass managedClass,
@Cached("getPropertyGetterWithFinalAssumption(cachedShape, key)") PropertyGetter getter,
@Exclusive @Cached LookupAttributeInMRONode.CachedKeyFastPath getDesc,
@Exclusive @Cached InlineWeakValueProfile slotsValueProfile) throws FastPathBailoutException, UnexpectedResultException {
return loadInstanceValueInt(inliningTarget, receiver, managedClass, key, getDesc, cachedShape, getter, slotsValueProfile);
}

@ForceQuickening
@Specialization(guards = {
"!hasMaterializedDict(cachedShape)", "managedClass != null || isBuiltinWithObjectOrModuleGetattro(cachedShape)", //
"getter != null", "getter.accepts(receiver)", //
"value != null"}, replaces = "doModule", limit = "3")
"getter != null", "getter.accepts(receiver)"}, //
replaces = "doInstanceValueInt", rewriteOn = FastPathBailoutException.class, limit = "3")
static Object doInstanceValue(TruffleString key, PythonObject receiver,
@Bind Node inliningTarget,
@Cached("receiver.getShape()") Shape cachedShape,
@Cached("getManagedClassOrNull(cachedShape)") PythonManagedClass managedClass,
@Cached("getPropertyGetterWithFinalAssumption(cachedShape, key)") PropertyGetter getter,
@Cached LookupAttributeInMRONode.CachedKeyFastPath getDesc,
@Cached InlineWeakValueProfile slotsValueProfile,
@Bind("loadInstanceValue(inliningTarget, receiver, managedClass, key, getDesc, cachedShape, getter, slotsValueProfile)") Object value) {
return value;
@Exclusive @Cached LookupAttributeInMRONode.CachedKeyFastPath getDesc,
@Exclusive @Cached InlineWeakValueProfile slotsValueProfile) throws FastPathBailoutException {
return loadInstanceValue(inliningTarget, receiver, managedClass, key, getDesc, cachedShape, getter, slotsValueProfile);
}

@Specialization(excludeForUncached = true, replaces = {"doInstanceValue", "doType"})
@Specialization(excludeForUncached = true, replaces = {"doModule", "doInstanceValue", "doType"})
@StoreBytecodeIndex
public static Object doIt(VirtualFrame frame,
TruffleString key,
Expand Down
Loading