Skip to content

Commit 680d09a

Browse files
committed
[GR-10753] Fix our distinction between builtin functions, functions, and methods
PullRequest: graalpython/111
2 parents 58adb3f + 618d260 commit 680d09a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+934
-414
lines changed

graalpython/com.oracle.graal.python.cext/src/methodobject.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ PyObject* PyCFunction_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module) {
5252
ml->ml_meth,
5353
get_method_flags_cwrapper(ml->ml_flags),
5454
get_method_flags_wrapper(ml->ml_flags),
55+
self,
56+
module,
5557
polyglot_from_string((const char*)(ml->ml_doc ? ml->ml_doc : ""), SRC_CS)));
5658
if (func == ERROR_MARKER) {
5759
return NULL;

graalpython/com.oracle.graal.python.test/src/com/oracle/graal/python/test/runtime/PythonModuleTests.java

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,22 @@
2525
*/
2626
package com.oracle.graal.python.test.runtime;
2727

28+
import static com.oracle.graal.python.nodes.BuiltinNames.__BUILTINS__;
29+
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__DOC__;
30+
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__NAME__;
31+
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__PACKAGE__;
32+
import static org.junit.Assert.assertEquals;
33+
34+
import org.junit.Test;
35+
2836
import com.oracle.graal.python.builtins.objects.function.PArguments;
29-
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
37+
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
3038
import com.oracle.graal.python.builtins.objects.module.PythonModule;
3139
import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass;
3240
import com.oracle.graal.python.nodes.BuiltinNames;
3341
import com.oracle.graal.python.nodes.call.InvokeNode;
3442
import com.oracle.graal.python.runtime.PythonContext;
3543
import com.oracle.graal.python.test.PythonTests;
36-
import org.junit.Test;
37-
38-
import static com.oracle.graal.python.nodes.BuiltinNames.__BUILTINS__;
39-
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__DOC__;
40-
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__NAME__;
41-
import static com.oracle.graal.python.nodes.SpecialAttributeNames.__PACKAGE__;
42-
import static org.junit.Assert.assertEquals;
4344

4445
public class PythonModuleTests {
4546

@@ -57,8 +58,8 @@ public void pythonModuleTest() {
5758
public void builtinsMinTest() {
5859
final PythonContext context = PythonTests.getContext();
5960
final PythonModule builtins = context.getBuiltins();
60-
PBuiltinFunction min = (PBuiltinFunction) builtins.getAttribute(BuiltinNames.MIN);
61-
Object returnValue = InvokeNode.create(min).invoke(createWithUserArguments(4, 2, 1));
61+
PBuiltinMethod min = (PBuiltinMethod) builtins.getAttribute(BuiltinNames.MIN);
62+
Object returnValue = InvokeNode.create(min).invoke(createWithUserArguments(builtins, 4, 2, 1));
6263
assertEquals(1, returnValue);
6364
}
6465

@@ -76,8 +77,8 @@ public void mainModuleTest() {
7677
final PythonContext context = PythonTests.getContext();
7778
PythonModule main = context.getMainModule();
7879
PythonModule builtins = (PythonModule) main.getAttribute(__BUILTINS__);
79-
PBuiltinFunction abs = (PBuiltinFunction) builtins.getAttribute(BuiltinNames.ABS);
80-
Object returned = InvokeNode.create(abs).invoke(createWithUserArguments(-42));
80+
PBuiltinMethod abs = (PBuiltinMethod) builtins.getAttribute(BuiltinNames.ABS);
81+
Object returned = InvokeNode.create(abs).invoke(createWithUserArguments(builtins, -42));
8182
assertEquals(42, returned);
8283
}
8384

graalpython/com.oracle.graal.python.test/src/tests/test_signal.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ def test_alarm():
8080
handler = lambda s,f: posix.close(s)
8181

8282
oldhandler = _signal.signal(_signal.SIGALRM, handler)
83-
assert oldhandler == _signal.SIG_DFL
84-
assert _signal.getsignal(_signal.SIGALRM) is handler
83+
assert oldhandler == _signal.SIG_DFL, "oldhandler != SIG_DFL"
84+
assert _signal.getsignal(_signal.SIGALRM) is handler, "getsignal handler != handler"
8585

8686
# schedule the alarm signal, that will trigger the handler, which
8787
# will in turn close our file

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/PythonLanguage.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import com.oracle.graal.python.builtins.objects.PythonAbstractObject;
3838
import com.oracle.graal.python.builtins.objects.function.PArguments;
3939
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
40+
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
4041
import com.oracle.graal.python.builtins.objects.module.PythonModule;
4142
import com.oracle.graal.python.builtins.objects.object.PythonObject;
4243
import com.oracle.graal.python.nodes.BuiltinNames;
@@ -386,10 +387,11 @@ protected Iterable<Scope> findTopScopes(PythonContext context) {
386387
@Override
387388
protected String toString(PythonContext context, Object value) {
388389
final PythonModule builtins = context.getBuiltins();
389-
PBuiltinFunction intClass = (PBuiltinFunction) builtins.getAttribute(BuiltinNames.REPR);
390-
Object[] userArgs = PArguments.create(1);
391-
PArguments.setArgument(userArgs, 0, value);
392-
Object res = InvokeNode.create(intClass).invoke(userArgs);
390+
PBuiltinFunction reprMethod = ((PBuiltinMethod) builtins.getAttribute(BuiltinNames.REPR)).getFunction();
391+
Object[] userArgs = PArguments.create(2);
392+
PArguments.setArgument(userArgs, 0, PNone.NONE);
393+
PArguments.setArgument(userArgs, 1, value);
394+
Object res = InvokeNode.create(reprMethod).invoke(userArgs);
393395
return res.toString();
394396
}
395397

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package com.oracle.graal.python.builtins;
42+
43+
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
44+
45+
public interface BoundBuiltinCallable<T> {
46+
T boundToObject(Object binding, PythonObjectFactory factory);
47+
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,11 @@
5656
String[] keywordArguments() default {};
5757

5858
boolean isPublic() default true;
59+
60+
/**
61+
* Module functions should be bound to their module, meaning they would take the module itself
62+
* as "self" parameter. We omit this by default, but if the builtin does explicitly specify the
63+
* self argument, set this to true.
64+
*/
65+
boolean declaresExplicitSelf() default false;
5966
}

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

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@
3232
public @interface CoreFunctions {
3333
String defineModule() default "";
3434

35-
String extendModule() default "";
36-
3735
String publicName() default "";
3836

3937
Class<?>[] extendClasses() default {};

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

Lines changed: 38 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@
100100
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
101101
import com.oracle.graal.python.builtins.objects.function.PFunction;
102102
import com.oracle.graal.python.builtins.objects.generator.GeneratorBuiltins;
103-
import com.oracle.graal.python.builtins.objects.getsetdescriptor.GetSetDescriptor;
104103
import com.oracle.graal.python.builtins.objects.getsetdescriptor.GetSetDescriptorTypeBuiltins;
105104
import com.oracle.graal.python.builtins.objects.ints.IntBuiltins;
106105
import com.oracle.graal.python.builtins.objects.ints.PInt;
@@ -112,6 +111,8 @@
112111
import com.oracle.graal.python.builtins.objects.list.PList;
113112
import com.oracle.graal.python.builtins.objects.mappingproxy.MappingproxyBuiltins;
114113
import com.oracle.graal.python.builtins.objects.memoryview.BufferBuiltins;
114+
import com.oracle.graal.python.builtins.objects.method.AbstractMethodBuiltins;
115+
import com.oracle.graal.python.builtins.objects.method.BuiltinMethodBuiltins;
115116
import com.oracle.graal.python.builtins.objects.method.MethodBuiltins;
116117
import com.oracle.graal.python.builtins.objects.module.PythonModule;
117118
import com.oracle.graal.python.builtins.objects.object.ObjectBuiltins;
@@ -232,7 +233,9 @@ public final class Python3Core implements PythonCore {
232233
new AbstractFunctionBuiltins(),
233234
new FunctionBuiltins(),
234235
new BuiltinFunctionBuiltins(),
236+
new AbstractMethodBuiltins(),
235237
new MethodBuiltins(),
238+
new BuiltinMethodBuiltins(),
236239
new CodeBuiltins(),
237240
new FrameBuiltins(),
238241
new MappingproxyBuiltins(),
@@ -621,9 +624,14 @@ private void initializeTypes() {
621624
addType(PythonObject.class, getObjectClass());
622625
addType(PythonModule.class, getModuleClass());
623626
addType(TruffleObject.class, getForeignClass());
624-
// n.b.: the builtin classes and their constructors are initialized first here, so we set up
625-
// the mapping from java classes to python classes.
627+
// n.b.: the builtin modules and classes and their constructors are initialized first here,
628+
// so we have the mapping from java classes to python classes and builtin names to modules
629+
// available.
626630
for (PythonBuiltins builtin : BUILTINS) {
631+
CoreFunctions annotation = builtin.getClass().getAnnotation(CoreFunctions.class);
632+
if (annotation.defineModule().length() > 0) {
633+
createModule(annotation.defineModule());
634+
}
627635
builtin.initializeClasses(this);
628636
for (Entry<PythonBuiltinClass, Entry<Class<?>[], Boolean>> entry : builtin.getBuiltinClasses().entrySet()) {
629637
PythonBuiltinClass pythonClass = entry.getKey();
@@ -639,109 +647,64 @@ private void populateBuiltins() {
639647
builtin.initialize(this);
640648
CoreFunctions annotation = builtin.getClass().getAnnotation(CoreFunctions.class);
641649
if (annotation.defineModule().length() > 0) {
642-
createModule(annotation.defineModule(), true, builtin);
643-
} else if (annotation.extendModule().length() > 0) {
644-
addBuiltinsToModule(builtinModules.get(annotation.extendModule()), builtin);
645-
} else if (annotation.extendClasses().length > 0) {
646-
for (Class<?> klass : annotation.extendClasses()) {
647-
addMethodsToType(klass, builtin);
648-
}
650+
addBuiltinsTo(builtinModules.get(annotation.defineModule()), builtin);
651+
}
652+
for (Class<?> klass : annotation.extendClasses()) {
653+
addBuiltinsTo(lookupType(klass), builtin);
649654
}
650655
}
651656

652657
// core machinery
653-
createModule("_descriptor", true);
654-
createModule("_warnings", true);
655-
PythonModule bootstrapExternal = createModule("importlib._bootstrap_external", "importlib");
658+
createModule("_descriptor");
659+
createModule("_warnings");
660+
PythonModule bootstrapExternal = createModule("importlib._bootstrap_external");
661+
bootstrapExternal.setAttribute(__PACKAGE__, "importlib");
656662
builtinModules.put("_frozen_importlib_external", bootstrapExternal);
657-
PythonModule bootstrap = createModule("importlib._bootstrap", "importlib");
663+
PythonModule bootstrap = createModule("importlib._bootstrap");
664+
bootstrap.setAttribute(__PACKAGE__, "importlib");
658665
builtinModules.put("_frozen_importlib", bootstrap);
659666
}
660667

661668
private void addType(Class<? extends Object> clazz, PythonBuiltinClass typ) {
662669
builtinTypes[PythonBuiltinClassType.fromClass(clazz).ordinal()] = typ;
663670
}
664671

665-
private PythonModule createModule(String name, String pkg, PythonBuiltins... builtins) {
666-
PythonModule mod = createModule(name, true, builtins);
667-
mod.setAttribute(__PACKAGE__, pkg);
668-
return mod;
669-
}
670-
671-
public PythonModule createModule(String name, boolean add, PythonBuiltins... builtins) {
672-
PythonModule mod = factory().createPythonModule(name);
673-
for (PythonBuiltins builtin : builtins) {
674-
addBuiltinsToModule(mod, builtin);
675-
}
676-
if (add) {
672+
private PythonModule createModule(String name) {
673+
PythonModule mod = builtinModules.get(name);
674+
if (mod == null) {
675+
mod = factory().createPythonModule(name);
677676
builtinModules.put(name, mod);
678677
}
679678
return mod;
680679
}
681680

682-
private PythonBuiltinClass addMethodsToType(Class<?> javaClass, PythonBuiltins... builtins) {
683-
return addMethodsToType(lookupType(javaClass), builtins);
684-
}
685-
686-
private PythonBuiltinClass addMethodsToType(PythonBuiltinClass clazz, PythonBuiltins... builtins) {
687-
for (PythonBuiltins builtin : builtins) {
688-
addBuiltinsToClass(clazz, builtin);
689-
}
690-
return clazz;
691-
}
692-
693-
private void addBuiltinsToModule(PythonModule mod, PythonBuiltins builtins) {
681+
private void addBuiltinsTo(PythonObject obj, PythonBuiltins builtins) {
694682
Map<String, Object> builtinConstants = builtins.getBuiltinConstants();
695683
for (Map.Entry<String, Object> entry : builtinConstants.entrySet()) {
696684
String constantName = entry.getKey();
697-
Object obj = entry.getValue();
698-
mod.setAttribute(constantName, obj);
685+
obj.setAttribute(constantName, entry.getValue());
699686
}
700687

701-
Map<String, PBuiltinFunction> builtinFunctions = builtins.getBuiltinFunctions();
702-
for (Map.Entry<String, PBuiltinFunction> entry : builtinFunctions.entrySet()) {
688+
Map<String, BoundBuiltinCallable<?>> builtinFunctions = builtins.getBuiltinFunctions();
689+
for (Entry<String, BoundBuiltinCallable<?>> entry : builtinFunctions.entrySet()) {
703690
String methodName = entry.getKey();
704-
PBuiltinFunction function = entry.getValue();
705-
mod.setAttribute(methodName, function);
691+
Object value;
692+
if (obj instanceof PythonModule) {
693+
value = factory.createBuiltinMethod(obj, (PBuiltinFunction) entry.getValue());
694+
} else {
695+
value = entry.getValue().boundToObject(obj, factory());
696+
}
697+
obj.setAttribute(methodName, value);
706698
}
707699

708700
Map<PythonBuiltinClass, Entry<Class<?>[], Boolean>> builtinClasses = builtins.getBuiltinClasses();
709701
for (Entry<PythonBuiltinClass, Entry<Class<?>[], Boolean>> entry : builtinClasses.entrySet()) {
710702
boolean isPublic = entry.getValue().getValue();
711-
Class<?>[] javaClasses = entry.getValue().getKey();
712-
PythonBuiltinClass pythonClass = entry.getKey();
713703
if (isPublic) {
714-
mod.setAttribute(pythonClass.getName(), pythonClass);
715-
}
716-
for (Class<?> klass : javaClasses) {
717-
addType(klass, pythonClass);
718-
}
719-
}
720-
}
721-
722-
private void addBuiltinsToClass(PythonBuiltinClass clazz, PythonBuiltins builtins) {
723-
Map<String, Object> builtinConstants = builtins.getBuiltinConstants();
724-
for (Map.Entry<String, Object> entry : builtinConstants.entrySet()) {
725-
String className = entry.getKey();
726-
Object obj = entry.getValue();
727-
if (obj instanceof GetSetDescriptor && ((GetSetDescriptor) obj).getType() != clazz) {
728-
// GetSetDescriptors need to be copied per class
729-
clazz.setAttributeUnsafe(className, factory().createGetSetDescriptor(
730-
((GetSetDescriptor) obj).getGet(),
731-
((GetSetDescriptor) obj).getSet(),
732-
((GetSetDescriptor) obj).getName(),
733-
clazz));
734-
} else {
735-
clazz.setAttributeUnsafe(className, obj);
704+
PythonBuiltinClass pythonClass = entry.getKey();
705+
obj.setAttribute(pythonClass.getName(), pythonClass);
736706
}
737707
}
738-
739-
Map<String, PBuiltinFunction> builtinFunctions = builtins.getBuiltinFunctions();
740-
for (Map.Entry<String, PBuiltinFunction> entry : builtinFunctions.entrySet()) {
741-
String className = entry.getKey();
742-
PBuiltinFunction function = entry.getValue();
743-
clazz.setAttributeUnsafe(className, function);
744-
}
745708
}
746709

747710
public Source getCoreSource(String basename) {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ public enum PythonBuiltinClassType {
3737
PArray(com.oracle.graal.python.builtins.objects.array.PArray.class, "array"),
3838
PBaseException(com.oracle.graal.python.builtins.objects.exception.PBaseException.class, "BaseException"),
3939
PBaseSetIterator(com.oracle.graal.python.builtins.objects.iterator.PBaseSetIterator.class, "iterator"),
40-
PBuiltinFunction(com.oracle.graal.python.builtins.objects.function.PBuiltinFunction.class, "builtin-function"),
41-
PBuiltinMethod(com.oracle.graal.python.builtins.objects.method.PBuiltinMethod.class, "method"),
40+
PBuiltinFunction(com.oracle.graal.python.builtins.objects.function.PBuiltinFunction.class, "method_descriptor"),
41+
PBuiltinMethod(com.oracle.graal.python.builtins.objects.method.PBuiltinMethod.class, "builtin_function_or_method"),
4242
PByteArray(com.oracle.graal.python.builtins.objects.bytes.PByteArray.class, "bytearray"),
4343
PBytes(com.oracle.graal.python.builtins.objects.bytes.PBytes.class, "bytes"),
4444
PCell(com.oracle.graal.python.builtins.objects.cell.PCell.class, "cell"),

0 commit comments

Comments
 (0)