Skip to content

Commit 63566e3

Browse files
committed
replace python-based __build_class__ with Java version
1 parent 2272d90 commit 63566e3

File tree

6 files changed

+219
-184
lines changed

6 files changed

+219
-184
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,6 @@ private static String[] initializeCoreFiles() {
273273
"code",
274274
"_io",
275275
"_frozen_importlib",
276-
"classes",
277276
"__graalpython__",
278277
"_weakref",
279278
"itertools",

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/BuiltinFunctions.java

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@
7979
import java.math.BigInteger;
8080
import java.nio.charset.Charset;
8181
import java.nio.charset.CodingErrorAction;
82+
import java.util.ArrayList;
83+
import java.util.Arrays;
8284
import java.util.List;
8385

8486
import com.oracle.graal.python.PythonFileDetector;
@@ -127,21 +129,27 @@
127129
import com.oracle.graal.python.nodes.ErrorMessages;
128130
import com.oracle.graal.python.nodes.GraalPythonTranslationErrorNode;
129131
import com.oracle.graal.python.nodes.PGuards;
132+
import com.oracle.graal.python.nodes.PNodeWithRaise;
130133
import com.oracle.graal.python.nodes.PRaiseNode;
131134
import com.oracle.graal.python.nodes.PRootNode;
135+
import com.oracle.graal.python.nodes.SpecialAttributeNames;
132136
import com.oracle.graal.python.nodes.SpecialMethodNames;
133137
import com.oracle.graal.python.nodes.argument.ReadArgumentNode;
134138
import com.oracle.graal.python.nodes.attributes.DeleteAttributeNode;
135139
import com.oracle.graal.python.nodes.attributes.GetAttributeNode.GetAnyAttributeNode;
136140
import com.oracle.graal.python.nodes.attributes.GetAttributeNode.GetFixedAttributeNode;
137141
import com.oracle.graal.python.nodes.attributes.HasInheritedAttributeNode;
142+
import com.oracle.graal.python.nodes.attributes.LookupAttributeInMRONode;
138143
import com.oracle.graal.python.nodes.attributes.LookupInheritedAttributeNode;
139144
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
140145
import com.oracle.graal.python.nodes.attributes.SetAttributeNode;
141146
import com.oracle.graal.python.nodes.builtins.ListNodes;
142147
import com.oracle.graal.python.nodes.builtins.ListNodes.ConstructListNode;
143148
import com.oracle.graal.python.nodes.call.CallNode;
144149
import com.oracle.graal.python.nodes.call.GenericInvokeNode;
150+
import com.oracle.graal.python.nodes.call.special.CallBinaryMethodNode;
151+
import com.oracle.graal.python.nodes.call.special.CallUnaryMethodNode;
152+
import com.oracle.graal.python.nodes.call.special.CallVarargsMethodNode;
145153
import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode;
146154
import com.oracle.graal.python.nodes.call.special.LookupAndCallTernaryNode;
147155
import com.oracle.graal.python.nodes.call.special.LookupAndCallUnaryNode;
@@ -160,9 +168,11 @@
160168
import com.oracle.graal.python.nodes.function.builtins.PythonTernaryBuiltinNode;
161169
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
162170
import com.oracle.graal.python.nodes.function.builtins.PythonUnaryClinicBuiltinNode;
171+
import com.oracle.graal.python.nodes.function.builtins.PythonVarargsBuiltinNode;
163172
import com.oracle.graal.python.nodes.function.builtins.clinic.ArgumentClinicProvider;
164173
import com.oracle.graal.python.nodes.object.GetClassNode;
165174
import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
175+
import com.oracle.graal.python.nodes.subscript.SetItemNode;
166176
import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
167177
import com.oracle.graal.python.nodes.util.CannotCastException;
168178
import com.oracle.graal.python.nodes.util.CastToJavaIntExactNode;
@@ -174,6 +184,8 @@
174184
import com.oracle.graal.python.runtime.PythonParser.ParserMode;
175185
import com.oracle.graal.python.runtime.exception.PException;
176186
import com.oracle.graal.python.runtime.exception.PythonErrorType;
187+
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
188+
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
177189
import com.oracle.graal.python.util.CharsetMapping;
178190
import com.oracle.graal.python.util.PythonUtils;
179191
import com.oracle.graal.python.util.Supplier;
@@ -183,10 +195,12 @@
183195
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
184196
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
185197
import com.oracle.truffle.api.RootCallTarget;
198+
import com.oracle.truffle.api.TruffleLanguage.ContextReference;
186199
import com.oracle.truffle.api.TruffleLanguage.LanguageReference;
187200
import com.oracle.truffle.api.debug.Debugger;
188201
import com.oracle.truffle.api.dsl.Cached;
189202
import com.oracle.truffle.api.dsl.Cached.Shared;
203+
import com.oracle.truffle.api.dsl.CachedContext;
190204
import com.oracle.truffle.api.dsl.Fallback;
191205
import com.oracle.truffle.api.dsl.GenerateNodeFactory;
192206
import com.oracle.truffle.api.dsl.ImportStatic;
@@ -1939,4 +1953,207 @@ protected ArgumentClinicProvider getArgumentClinic() {
19391953
return BuiltinFunctionsClinicProviders.OpenNodeClinicProviderGen.INSTANCE;
19401954
}
19411955
}
1956+
1957+
@ImportStatic(SpecialMethodNames.class)
1958+
abstract static class UpdateBasesNode extends PNodeWithRaise {
1959+
1960+
abstract PTuple execute(VirtualFrame frame, PTuple bases, Object[] arguments, int nargs);
1961+
1962+
@Specialization
1963+
PTuple update(VirtualFrame frame, PTuple bases, Object[] arguments, int nargs,
1964+
@Cached PythonObjectFactory factory,
1965+
@CachedLibrary(limit = "3") InteropLibrary interop,
1966+
@Cached GetClassNode getMroClass,
1967+
@Cached(parameters = "__MRO_ENTRIES__") LookupAttributeInMRONode getMroEntries,
1968+
@Cached CallBinaryMethodNode callMroEntries) {
1969+
ArrayList<Object> newBases = null;
1970+
for (int i = 0; i < nargs; i++) {
1971+
Object base = arguments[i];
1972+
if (PGuards.isClass(base, interop)) {
1973+
if (newBases != null) {
1974+
// If we already have made a replacement, then we append every normal base,
1975+
// otherwise just skip it.
1976+
newBases.add(base);
1977+
}
1978+
continue;
1979+
}
1980+
1981+
Object meth = getMroEntries.execute(getMroClass.execute(base));
1982+
if (PGuards.isNoValue(meth)) {
1983+
if (newBases != null) {
1984+
newBases.add(base);
1985+
}
1986+
continue;
1987+
}
1988+
Object newBase = callMroEntries.executeObject(frame, meth, base, bases);
1989+
if (newBase == null) {
1990+
// error
1991+
return null;
1992+
}
1993+
if (!PGuards.isPTuple(newBase)) {
1994+
throw raise(PythonErrorType.TypeError, "__mro_entries__ must return a tuple");
1995+
}
1996+
PTuple newBaseTuple = (PTuple) newBase;
1997+
if (newBases == null) {
1998+
// If this is a first successful replacement, create new_bases list and copy
1999+
// previously encountered bases.
2000+
newBases = new ArrayList<>();
2001+
for (int j = 0; j < i; j++) {
2002+
newBases.add(arguments[j]);
2003+
}
2004+
}
2005+
SequenceStorage storage = newBaseTuple.getSequenceStorage();
2006+
for (int j = 0; j < storage.length(); j++) {
2007+
newBases.add(storage.getItemNormalized(j));
2008+
}
2009+
}
2010+
if (newBases == null) {
2011+
return bases;
2012+
}
2013+
return factory.createTuple(newBases.toArray());
2014+
}
2015+
}
2016+
2017+
abstract static class CalculateMetaclassNode extends PNodeWithRaise {
2018+
2019+
abstract Object execute(Object metatype, PTuple bases);
2020+
2021+
/* Determine the most derived metatype. */
2022+
@Specialization
2023+
Object calculate(Object metatype, PTuple bases,
2024+
@Cached GetClassNode getClass,
2025+
@Cached IsSubtypeNode isSubType,
2026+
@Cached IsSubtypeNode isSubTypeReverse) {
2027+
/*
2028+
* Determine the proper metatype to deal with this, and check for metatype conflicts
2029+
* while we're at it. Note that if some other metatype wins to contract, it's possible
2030+
* that its instances are not types.
2031+
*/
2032+
2033+
SequenceStorage storage = bases.getSequenceStorage();
2034+
int nbases = storage.length();
2035+
Object winner = metatype;
2036+
for (int i = 0; i < nbases; i++) {
2037+
Object tmp = storage.getItemNormalized(i);
2038+
Object tmpType = getClass.execute(tmp);
2039+
if (isSubType.execute(winner, tmpType)) {
2040+
// nothing to do
2041+
} else if (isSubTypeReverse.execute(tmpType, winner)) {
2042+
winner = tmpType;
2043+
} else {
2044+
throw raise(PythonErrorType.TypeError, ErrorMessages.METACLASS_CONFLICT);
2045+
}
2046+
}
2047+
return winner;
2048+
}
2049+
}
2050+
2051+
@Builtin(name = BuiltinNames.__BUILD_CLASS__, minNumOfPositionalArgs = 1, takesVarArgs = true, takesVarKeywordArgs = true)
2052+
@GenerateNodeFactory
2053+
public abstract static class BuildClassNode extends PythonVarargsBuiltinNode {
2054+
@Child private com.oracle.graal.python.nodes.call.CallNode callNode = com.oracle.graal.python.nodes.call.CallNode.create();
2055+
2056+
@Specialization
2057+
protected Object doItNonFunction(VirtualFrame frame, Object function, Object[] arguments, PKeyword[] keywords,
2058+
@CachedContext(PythonLanguage.class) ContextReference<PythonContext> contextRef,
2059+
@CachedLibrary(limit = "3") InteropLibrary interop,
2060+
@Cached CastToJavaStringNode castToString,
2061+
@Cached PythonObjectFactory factory,
2062+
@Cached CalculateMetaclassNode calculateMetaClass,
2063+
@Cached(parameters = "__PREPARE__") LookupAttributeInMRONode getPrepare,
2064+
@Cached GetClassNode getGetItemClass,
2065+
@Cached(parameters = "__GETITEM__") LookupAttributeInMRONode getGetItem,
2066+
@Cached CallVarargsMethodNode callPrep,
2067+
@Cached CallVarargsMethodNode callType,
2068+
@Cached CallUnaryMethodNode callBody,
2069+
@Cached UpdateBasesNode update,
2070+
@Cached SetItemNode setOrigBases,
2071+
@Cached GetClassNode getClass) {
2072+
2073+
boolean isClass = false;
2074+
2075+
if (arguments.length < 1) {
2076+
throw raise(PythonErrorType.TypeError, "__build_class__: not enough arguments");
2077+
}
2078+
2079+
if (!PGuards.isFunction(function)) {
2080+
throw raise(PythonErrorType.TypeError, "__build_class__: func must be a function");
2081+
}
2082+
String name;
2083+
try {
2084+
name = castToString.execute(arguments[0]);
2085+
} catch (CannotCastException e) {
2086+
throw raise(PythonErrorType.TypeError, "__build_class__: name is not a string");
2087+
}
2088+
2089+
Object[] basesArray = Arrays.copyOfRange(arguments, 1, arguments.length);
2090+
PTuple origBases = factory.createTuple(basesArray);
2091+
2092+
PTuple bases = update.execute(frame, origBases, basesArray, basesArray.length);
2093+
2094+
Object meta = null;
2095+
PKeyword[] mkw = keywords;
2096+
if (keywords.length > 0) {
2097+
for (int i = 0; i < keywords.length; i++) {
2098+
if ("metaclass".equals(keywords[i].getName())) {
2099+
meta = keywords[i].getValue();
2100+
mkw = new PKeyword[keywords.length - 1];
2101+
System.arraycopy(keywords, 0, mkw, 0, i);
2102+
System.arraycopy(keywords, i + 1, mkw, i, mkw.length - i);
2103+
2104+
// metaclass is explicitly given, check if it's indeed a class
2105+
isClass = PGuards.isClass(meta, interop);
2106+
break;
2107+
}
2108+
}
2109+
}
2110+
if (meta == null) {
2111+
// if there are no bases, use type:
2112+
if (bases.getSequenceStorage().length() == 0) {
2113+
meta = contextRef.get().getCore().lookupType(PythonBuiltinClassType.PythonClass);
2114+
} else {
2115+
// else get the type of the first base
2116+
meta = getClass.execute(bases.getSequenceStorage().getItemNormalized(0));
2117+
}
2118+
isClass = true; // meta is really a class
2119+
}
2120+
2121+
if (isClass) {
2122+
// meta is really a class, so check for a more derived metaclass, or possible
2123+
// metaclass conflicts:
2124+
meta = calculateMetaClass.execute(meta, bases);
2125+
}
2126+
// else: meta is not a class, so we cannot do the metaclass calculation, so we will
2127+
// use the explicitly given object as it is
2128+
Object prep = getPrepare.execute(meta);
2129+
Object ns;
2130+
if (PGuards.isNoValue(prep)) {
2131+
ns = factory.createDict();
2132+
} else {
2133+
if (PGuards.isFunction(prep)) {
2134+
ns = callPrep.execute(frame, prep, new Object[]{name, bases}, mkw);
2135+
} else {
2136+
ns = callPrep.execute(frame, prep, new Object[]{meta, name, bases}, mkw);
2137+
}
2138+
}
2139+
if (PGuards.isNoValue(getGetItem.execute(getGetItemClass.execute(ns)))) {
2140+
if (isClass) {
2141+
throw raise(PythonErrorType.TypeError, "%p.__prepare__() must return a mapping, not %p", meta, ns);
2142+
} else {
2143+
throw raise(PythonErrorType.TypeError, "<metaclass>.__prepare__() must return a mapping, not %p", ns);
2144+
}
2145+
}
2146+
callBody.executeObject(frame, function, ns);
2147+
if (bases != origBases) {
2148+
setOrigBases.executeWith(frame, ns, SpecialAttributeNames.__ORIG_BASES__, origBases);
2149+
}
2150+
Object cls = callType.execute(frame, meta, new Object[]{name, bases, ns}, mkw);
2151+
2152+
/*
2153+
* We could check here and throw "__class__ not set defining..." errors.
2154+
*/
2155+
2156+
return cls;
2157+
}
2158+
}
19422159
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/SpecialAttributeNames.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,5 @@ public abstract class SpecialAttributeNames {
8383
public static final String __ALL__ = "__all__";
8484
public static final String __FLAGS__ = "__flags__";
8585
public static final String __ABSTRACTMETHODS__ = "__abstractmethods__";
86+
public static final String __ORIG_BASES__ = "__orig_bases__";
8687
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/SpecialMethodNames.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ public abstract class SpecialMethodNames {
159159
public static final String __SETFORMAT__ = "__setformat__";
160160
public static final String __OBJCLASS__ = "__objclass__";
161161
public static final String __ISABSTRACTMETHOD__ = "__isabstractmethod__";
162+
public static final String __MRO_ENTRIES__ = "__mro_entries__";
162163
public static final String KEYS = "keys";
163164
public static final String ITEMS = "items";
164165
public static final String VALUES = "values";

0 commit comments

Comments
 (0)