Skip to content

Commit 6ff3fe0

Browse files
committed
intrinsify print function
1 parent 30c6aaf commit 6ff3fe0

File tree

4 files changed

+107
-53
lines changed

4 files changed

+107
-53
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@
131131
import com.oracle.graal.python.builtins.objects.method.ClassmethodBuiltins;
132132
import com.oracle.graal.python.builtins.objects.method.DecoratedMethodBuiltins;
133133
import com.oracle.graal.python.builtins.objects.method.MethodBuiltins;
134+
import com.oracle.graal.python.builtins.objects.method.PBuiltinMethod;
134135
import com.oracle.graal.python.builtins.objects.method.StaticmethodBuiltins;
135136
import com.oracle.graal.python.builtins.objects.module.PythonModule;
136137
import com.oracle.graal.python.builtins.objects.object.ObjectBuiltins;
@@ -155,6 +156,7 @@
155156
import com.oracle.graal.python.builtins.objects.type.PythonClass;
156157
import com.oracle.graal.python.builtins.objects.type.TypeBuiltins;
157158
import com.oracle.graal.python.builtins.objects.zipimporter.ZipImporterBuiltins;
159+
import com.oracle.graal.python.nodes.SpecialAttributeNames;
158160
import com.oracle.graal.python.runtime.PythonContext;
159161
import com.oracle.graal.python.runtime.PythonCore;
160162
import com.oracle.graal.python.runtime.PythonOptions;

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

Lines changed: 101 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@
123123
import com.oracle.graal.python.nodes.argument.ReadIndexedArgumentNode;
124124
import com.oracle.graal.python.nodes.argument.ReadVarArgsNode;
125125
import com.oracle.graal.python.nodes.attributes.DeleteAttributeNode;
126+
import com.oracle.graal.python.nodes.attributes.GetAttributeNode;
126127
import com.oracle.graal.python.nodes.attributes.HasInheritedAttributeNode;
127128
import com.oracle.graal.python.nodes.attributes.LookupInheritedAttributeNode;
128129
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
@@ -153,15 +154,16 @@
153154
import com.oracle.graal.python.nodes.subscript.GetItemNode;
154155
import com.oracle.graal.python.nodes.truffle.PythonArithmeticTypes;
155156
import com.oracle.graal.python.nodes.util.CastToIntegerFromIndexNode;
156-
import com.oracle.graal.python.runtime.PythonContext;
157+
import com.oracle.graal.python.nodes.util.CastToStringNode;
157158
import com.oracle.graal.python.runtime.PythonCore;
158159
import com.oracle.graal.python.runtime.PythonOptions;
159160
import com.oracle.graal.python.runtime.PythonParser.ParserMode;
160161
import com.oracle.graal.python.runtime.exception.PException;
161162
import com.oracle.graal.python.runtime.exception.PythonErrorType;
162163
import com.oracle.graal.python.runtime.sequence.PSequence;
163-
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
164+
import com.oracle.truffle.api.Assumption;
164165
import com.oracle.truffle.api.CompilerDirectives;
166+
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
165167
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
166168
import com.oracle.truffle.api.Truffle;
167169
import com.oracle.truffle.api.dsl.Cached;
@@ -1326,45 +1328,113 @@ public int ord(PBytes chr,
13261328
}
13271329

13281330
// print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
1329-
@Builtin(name = PRINT, fixedNumOfPositionalArgs = 5)
1331+
@Builtin(name = PRINT, takesVarArgs = true, keywordArguments = {"sep", "end", "file", "flush"}, doc = "\n" +
1332+
"print(value, ..., sep=' ', end='\\n', file=sys.stdout, flush=False)\n" +
1333+
"\n" +
1334+
"Prints the values to a stream, or to sys.stdout by default.\n" +
1335+
"Optional keyword arguments:\n" +
1336+
"file: a file-like object (stream); defaults to the current sys.stdout.\n" +
1337+
"sep: string inserted between values, default a space.\n" +
1338+
"end: string appended after the last value, default a newline.\n" +
1339+
"flush: whether to forcibly flush the stream.")
13301340
@GenerateNodeFactory
13311341
public abstract static class PrintNode extends PythonBuiltinNode {
1332-
@SuppressWarnings("unused")
1342+
private static final String DEFAULT_END = "\n";
1343+
private static final String DEFAULT_SEPARATOR = " ";
1344+
@Child ReadAttributeFromObjectNode readStdout;
1345+
@Child GetAttributeNode getWrite = GetAttributeNode.create("write", null);
1346+
@Child CallNode callWrite = CallNode.create();
1347+
@Child CastToStringNode toString = CastToStringNode.createCoercing();
1348+
@Child private LookupAndCallUnaryNode callFlushNode;
1349+
@CompilationFinal private Assumption singleContextAssumption;
1350+
@CompilationFinal private PythonModule cachedSys;
1351+
13331352
@Specialization
1334-
public Object print(PTuple values, String sep, String end, Object file, boolean flush,
1335-
@Cached("create()") SequenceStorageNodes.LenNode lenNode,
1336-
@Cached("createNotNormalized()") SequenceStorageNodes.GetItemNode getItemNode,
1337-
@Cached("create(__STR__)") LookupAndCallUnaryNode callStr) {
1338-
try {
1339-
PythonContext context = getContext();
1340-
if (lenNode.execute(values.getSequenceStorage()) == 0) {
1341-
write(context, end);
1342-
} else {
1343-
SequenceStorage store = values.getSequenceStorage();
1344-
StringBuilder sb = new StringBuilder();
1345-
for (int i = 0; i < store.length() - 1; i++) {
1346-
append(sb, callStr.executeObject(getItemNode.execute(store, i)));
1347-
append(sb, " ");
1348-
}
1349-
append(sb, callStr.executeObject(getItemNode.execute(store, store.length() - 1)));
1350-
append(sb, end);
1351-
write(context, sb.toString());
1353+
PNone printNoKeywords(VirtualFrame frame, Object[] values, @SuppressWarnings("unused") PNone sep, @SuppressWarnings("unused") PNone end, @SuppressWarnings("unused") PNone file,
1354+
@SuppressWarnings("unused") PNone flush) {
1355+
Object stdout = getStdout();
1356+
return printAllGiven(frame, values, DEFAULT_SEPARATOR, DEFAULT_END, stdout, false);
1357+
}
1358+
1359+
@Specialization(guards = {"!isNone(file)", "!isNoValue(file)"})
1360+
PNone printAllGiven(VirtualFrame frame, Object[] values, String sep, String end, Object file, boolean flush) {
1361+
int lastValue = values.length - 1;
1362+
Object write = getWrite.executeObject(file);
1363+
for (int i = 0; i < lastValue; i++) {
1364+
callWrite.execute(frame, write, toString.execute(values[i]));
1365+
callWrite.execute(frame, write, sep);
1366+
}
1367+
if (lastValue >= 0) {
1368+
callWrite.execute(frame, write, toString.execute(values[lastValue]));
1369+
}
1370+
callWrite.execute(frame, write, end);
1371+
if (flush) {
1372+
if (callFlushNode == null) {
1373+
CompilerDirectives.transferToInterpreterAndInvalidate();
1374+
callFlushNode = insert(LookupAndCallUnaryNode.create("flush"));
13521375
}
1353-
} catch (IOException e) {
1354-
// pass through
1376+
callFlushNode.executeObject(file);
13551377
}
1356-
13571378
return PNone.NONE;
13581379
}
13591380

1360-
@TruffleBoundary(transferToInterpreterOnException = false)
1361-
private static void append(StringBuilder sb, Object o) {
1362-
sb.append(o);
1381+
@Specialization(replaces = {"printAllGiven", "printNoKeywords"})
1382+
PNone printGeneric(VirtualFrame frame, Object[] values, Object sepIn, Object endIn, Object fileIn, Object flushIn,
1383+
@Cached("createCoercing()") CastToStringNode castSep,
1384+
@Cached("createCoercing()") CastToStringNode castEnd,
1385+
@Cached("createIfTrueNode()") CastToBooleanNode castFlush) {
1386+
String sep;
1387+
if (sepIn instanceof PNone) {
1388+
sep = DEFAULT_SEPARATOR;
1389+
} else {
1390+
sep = castSep.execute(sepIn);
1391+
}
1392+
String end;
1393+
if (endIn instanceof PNone) {
1394+
end = DEFAULT_END;
1395+
} else {
1396+
end = castEnd.execute(endIn);
1397+
}
1398+
Object file;
1399+
if (fileIn instanceof PNone) {
1400+
file = getStdout();
1401+
} else {
1402+
file = fileIn;
1403+
}
1404+
boolean flush;
1405+
if (flushIn instanceof PNone) {
1406+
flush = false;
1407+
} else {
1408+
flush = castFlush.executeWith(flushIn);
1409+
}
1410+
return printAllGiven(frame, values, sep, end, file, flush);
13631411
}
13641412

1365-
@TruffleBoundary
1366-
private static void write(PythonContext context, String string) throws IOException {
1367-
context.getStandardOut().write(string.getBytes());
1413+
private Object getStdout() {
1414+
if (singleContextAssumption == null) {
1415+
CompilerDirectives.transferToInterpreterAndInvalidate();
1416+
singleContextAssumption = singleContextAssumption();
1417+
}
1418+
PythonModule sys;
1419+
if (singleContextAssumption.isValid()) {
1420+
if (cachedSys == null) {
1421+
CompilerDirectives.transferToInterpreterAndInvalidate();
1422+
cachedSys = getContext().getCore().lookupBuiltinModule("sys");
1423+
}
1424+
sys = cachedSys;
1425+
} else {
1426+
if (cachedSys != null) {
1427+
CompilerDirectives.transferToInterpreterAndInvalidate();
1428+
cachedSys = null;
1429+
}
1430+
sys = getContext().getCore().lookupBuiltinModule("sys");
1431+
}
1432+
if (readStdout == null) {
1433+
CompilerDirectives.transferToInterpreterAndInvalidate();
1434+
readStdout = insert(ReadAttributeFromObjectNode.create());
1435+
}
1436+
Object stdout = readStdout.execute(sys, "stdout");
1437+
return stdout;
13681438
}
13691439
}
13701440

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/call/CallNode.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ public static CallNode create() {
7474

7575
public abstract Object execute(VirtualFrame frame, Object callableObject, Object[] arguments, PKeyword[] keywords);
7676

77+
public final Object execute(VirtualFrame frame, Object callableObject, Object... arguments) {
78+
return execute(frame, callableObject, arguments, PKeyword.EMPTY_KEYWORDS);
79+
}
80+
7781
protected static boolean isNoCallable(Object callee) {
7882
return !(callee instanceof PythonCallable);
7983
}

graalpython/lib-graalpython/functions.py

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -46,28 +46,6 @@ def hasattr(obj, key):
4646
return False
4747

4848

49-
# We re-define the print function here, because that makes it easier for us to
50-
# deal with the default arguments. The builtin version simply requires all
51-
# arguments.
52-
def make_print():
53-
builtin_print = print
54-
55-
def print_f(*objects, sep=" ", end="\n", file=None, flush=False):
56-
if file is not None:
57-
sz = len(objects) - 1
58-
for i in range(sz):
59-
file.write(str(objects[i]))
60-
file.write(str(sep))
61-
file.write(str(objects[-1]))
62-
file.write(str(end))
63-
else:
64-
builtin_print(tuple(objects), sep, end, file, flush)
65-
print_f.__name__ = "print"
66-
return print_f
67-
print = __builtin__(make_print())
68-
del make_print
69-
70-
7149
@__builtin__
7250
def any(iterable):
7351
for i in iterable:

0 commit comments

Comments
 (0)